private_api_drive.cc revision 010d83a9304c5a91596085d917d248abff47903a
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.
4
5#include "chrome/browser/chromeos/extensions/file_manager/private_api_drive.h"
6
7#include "chrome/browser/browser_process.h"
8#include "chrome/browser/chromeos/drive/drive_integration_service.h"
9#include "chrome/browser/chromeos/extensions/file_manager/private_api_util.h"
10#include "chrome/browser/chromeos/file_manager/file_tasks.h"
11#include "chrome/browser/chromeos/file_manager/fileapi_util.h"
12#include "chrome/browser/chromeos/file_manager/url_util.h"
13#include "chrome/browser/chromeos/fileapi/file_system_backend.h"
14#include "chrome/browser/chromeos/login/user_manager.h"
15#include "chrome/browser/drive/drive_app_registry.h"
16#include "chrome/browser/drive/event_logger.h"
17#include "chrome/browser/profiles/profile.h"
18#include "chrome/browser/profiles/profile_manager.h"
19#include "chrome/common/extensions/api/file_browser_private.h"
20#include "content/public/browser/browser_thread.h"
21#include "webkit/common/fileapi/file_system_info.h"
22#include "webkit/common/fileapi/file_system_util.h"
23
24using content::BrowserThread;
25
26using file_manager::util::EntryDefinition;
27using file_manager::util::EntryDefinitionCallback;
28using file_manager::util::EntryDefinitionList;
29using file_manager::util::EntryDefinitionListCallback;
30using file_manager::util::FileDefinition;
31using file_manager::util::FileDefinitionList;
32using extensions::api::file_browser_private::DriveEntryProperties;
33
34namespace extensions {
35namespace {
36
37// List of connection types of drive.
38// Keep this in sync with the DriveConnectionType in common/js/util.js.
39const char kDriveConnectionTypeOffline[] = "offline";
40const char kDriveConnectionTypeMetered[] = "metered";
41const char kDriveConnectionTypeOnline[] = "online";
42
43// List of reasons of kDriveConnectionType*.
44// Keep this in sync with the DriveConnectionReason in common/js/util.js.
45const char kDriveConnectionReasonNotReady[] = "not_ready";
46const char kDriveConnectionReasonNoNetwork[] = "no_network";
47const char kDriveConnectionReasonNoService[] = "no_service";
48
49// Copies properties from |entry_proto| to |properties|. |shared_with_me| is
50// given from the running profile.
51void FillDriveEntryPropertiesValue(const drive::ResourceEntry& entry_proto,
52                                   bool shared_with_me,
53                                   DriveEntryProperties* properties) {
54  properties->shared_with_me.reset(new bool(shared_with_me));
55  properties->shared.reset(new bool(entry_proto.shared()));
56
57  const drive::PlatformFileInfoProto& file_info = entry_proto.file_info();
58  properties->file_size.reset(new double(file_info.size()));
59  properties->last_modified_time.reset(new double(
60      base::Time::FromInternalValue(file_info.last_modified()).ToJsTime()));
61
62  if (!entry_proto.has_file_specific_info())
63    return;
64
65  const drive::FileSpecificInfo& file_specific_info =
66      entry_proto.file_specific_info();
67
68  if (!entry_proto.resource_id().empty()) {
69    properties->thumbnail_url.reset(
70        new std::string("https://www.googledrive.com/thumb/" +
71                        entry_proto.resource_id() + "?width=500&height=500"));
72  }
73  if (file_specific_info.has_image_width()) {
74    properties->image_width.reset(
75        new int(file_specific_info.image_width()));
76  }
77  if (file_specific_info.has_image_height()) {
78    properties->image_height.reset(
79        new int(file_specific_info.image_height()));
80  }
81  if (file_specific_info.has_image_rotation()) {
82    properties->image_rotation.reset(
83        new int(file_specific_info.image_rotation()));
84  }
85  properties->is_hosted.reset(
86      new bool(file_specific_info.is_hosted_document()));
87  properties->content_mime_type.reset(
88      new std::string(file_specific_info.content_mime_type()));
89}
90
91// Creates entry definition list for (metadata) search result info list.
92template <class T>
93void ConvertSearchResultInfoListToEntryDefinitionList(
94    Profile* profile,
95    const std::string& extension_id,
96    const std::vector<T>& search_result_info_list,
97    const EntryDefinitionListCallback& callback) {
98  FileDefinitionList file_definition_list;
99
100  for (size_t i = 0; i < search_result_info_list.size(); ++i) {
101    FileDefinition file_definition;
102    file_definition.virtual_path =
103        file_manager::util::ConvertDrivePathToRelativeFileSystemPath(
104            profile, extension_id, search_result_info_list.at(i).path);
105    file_definition.is_directory = search_result_info_list.at(i).is_directory;
106    file_definition_list.push_back(file_definition);
107  }
108
109  file_manager::util::ConvertFileDefinitionListToEntryDefinitionList(
110      profile,
111      extension_id,
112      file_definition_list,  // Safe, since copied internally.
113      callback);
114}
115
116class SingleDriveEntryPropertiesGetter {
117 public:
118  typedef base::Callback<void(drive::FileError error)> ResultCallback;
119
120  // Creates an instance and starts the process.
121  static void Start(const base::FilePath local_path,
122                    linked_ptr<DriveEntryProperties> properties,
123                    Profile* const profile,
124                    const ResultCallback& callback) {
125
126    SingleDriveEntryPropertiesGetter* instance =
127        new SingleDriveEntryPropertiesGetter(
128            local_path, properties, profile, callback);
129    instance->StartProcess();
130
131    // The instance will be destroyed by itself.
132  }
133
134  virtual ~SingleDriveEntryPropertiesGetter() {}
135
136 private:
137  // Given parameters.
138  const ResultCallback callback_;
139  const base::FilePath local_path_;
140  const linked_ptr<DriveEntryProperties> properties_;
141  Profile* const running_profile_;
142
143  // Values used in the process.
144  Profile* file_owner_profile_;
145  base::FilePath file_path_;
146  scoped_ptr<drive::ResourceEntry> owner_resource_entry_;
147
148  base::WeakPtrFactory<SingleDriveEntryPropertiesGetter> weak_ptr_factory_;
149
150  SingleDriveEntryPropertiesGetter(const base::FilePath local_path,
151                                   linked_ptr<DriveEntryProperties> properties,
152                                   Profile* const profile,
153                                   const ResultCallback& callback)
154      : callback_(callback),
155        local_path_(local_path),
156        properties_(properties),
157        running_profile_(profile),
158        file_owner_profile_(NULL),
159        weak_ptr_factory_(this) {
160    DCHECK(!callback_.is_null());
161    DCHECK(profile);
162  }
163
164  base::WeakPtr<SingleDriveEntryPropertiesGetter> GetWeakPtr() {
165    return weak_ptr_factory_.GetWeakPtr();
166  }
167
168  void StartProcess() {
169    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
170
171    file_path_ = drive::util::ExtractDrivePath(local_path_);
172    file_owner_profile_ = drive::util::ExtractProfileFromPath(local_path_);
173
174    if (!file_owner_profile_ ||
175        !g_browser_process->profile_manager()->IsValidProfile(
176            file_owner_profile_)) {
177      CompleteGetFileProperties(drive::FILE_ERROR_FAILED);
178      return;
179    }
180
181    // Start getting the file info.
182    drive::FileSystemInterface* const file_system =
183        drive::util::GetFileSystemByProfile(file_owner_profile_);
184    if (!file_system) {
185      // |file_system| is NULL if Drive is disabled or not mounted.
186      CompleteGetFileProperties(drive::FILE_ERROR_FAILED);
187      return;
188    }
189
190    file_system->GetResourceEntry(
191        file_path_,
192        base::Bind(&SingleDriveEntryPropertiesGetter::OnGetFileInfo,
193                   GetWeakPtr()));
194  }
195
196  void OnGetFileInfo(drive::FileError error,
197                     scoped_ptr<drive::ResourceEntry> entry) {
198    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
199
200    if (error != drive::FILE_ERROR_OK) {
201      CompleteGetFileProperties(error);
202      return;
203    }
204
205    DCHECK(entry);
206    owner_resource_entry_.swap(entry);
207
208    if (running_profile_->IsSameProfile(file_owner_profile_)) {
209      StartParseFileInfo(owner_resource_entry_->shared_with_me());
210      return;
211    }
212
213    // If the running profile does not own the file, obtain the shared_with_me
214    // flag from the running profile's value.
215    drive::FileSystemInterface* const file_system =
216        drive::util::GetFileSystemByProfile(running_profile_);
217    if (!file_system) {
218      CompleteGetFileProperties(drive::FILE_ERROR_FAILED);
219      return;
220    }
221    file_system->GetPathFromResourceId(
222        owner_resource_entry_->resource_id(),
223        base::Bind(&SingleDriveEntryPropertiesGetter::OnGetRunningPath,
224                   GetWeakPtr()));
225  }
226
227  void OnGetRunningPath(drive::FileError error,
228                        const base::FilePath& file_path) {
229    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
230
231    if (error != drive::FILE_ERROR_OK) {
232      // The running profile does not know the file.
233      StartParseFileInfo(false);
234      return;
235    }
236
237    drive::FileSystemInterface* const file_system =
238        drive::util::GetFileSystemByProfile(running_profile_);
239    if (!file_system) {
240      // The drive is disable for the running profile.
241      StartParseFileInfo(false);
242      return;
243    }
244
245    file_system->GetResourceEntry(
246        file_path,
247        base::Bind(&SingleDriveEntryPropertiesGetter::OnGetShareInfo,
248                   GetWeakPtr()));
249  }
250
251  void OnGetShareInfo(drive::FileError error,
252                      scoped_ptr<drive::ResourceEntry> entry) {
253    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
254
255    if (error != drive::FILE_ERROR_OK) {
256      CompleteGetFileProperties(error);
257      return;
258    }
259
260    DCHECK(entry);
261    StartParseFileInfo(entry->shared_with_me());
262  }
263
264  void StartParseFileInfo(bool shared_with_me) {
265    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
266
267    FillDriveEntryPropertiesValue(
268        *owner_resource_entry_, shared_with_me, properties_.get());
269
270    drive::FileSystemInterface* const file_system =
271        drive::util::GetFileSystemByProfile(file_owner_profile_);
272    drive::DriveAppRegistry* const app_registry =
273        drive::util::GetDriveAppRegistryByProfile(file_owner_profile_);
274    if (!file_system || !app_registry) {
275      // |file_system| or |app_registry| is NULL if Drive is disabled.
276      CompleteGetFileProperties(drive::FILE_ERROR_FAILED);
277      return;
278    }
279
280    // The properties meaningful for directories are already filled in
281    // FillDriveEntryPropertiesValue().
282    if (!owner_resource_entry_->has_file_specific_info()) {
283      CompleteGetFileProperties(drive::FILE_ERROR_OK);
284      return;
285    }
286
287    const drive::FileSpecificInfo& file_specific_info =
288        owner_resource_entry_->file_specific_info();
289
290    // Get drive WebApps that can accept this file. We just need to extract the
291    // doc icon for the drive app, which is set as default.
292    std::vector<drive::DriveAppInfo> drive_apps;
293    app_registry->GetAppsForFile(file_path_.Extension(),
294                                 file_specific_info.content_mime_type(),
295                                 &drive_apps);
296    if (!drive_apps.empty()) {
297      std::string default_task_id =
298          file_manager::file_tasks::GetDefaultTaskIdFromPrefs(
299              *file_owner_profile_->GetPrefs(),
300              file_specific_info.content_mime_type(),
301              file_path_.Extension());
302      file_manager::file_tasks::TaskDescriptor default_task;
303      file_manager::file_tasks::ParseTaskID(default_task_id, &default_task);
304      DCHECK(default_task_id.empty() || !default_task.app_id.empty());
305      for (size_t i = 0; i < drive_apps.size(); ++i) {
306        const drive::DriveAppInfo& app_info = drive_apps[i];
307        if (default_task.app_id == app_info.app_id) {
308          // The drive app is set as default. Files.app should use the doc icon.
309          const GURL doc_icon = drive::util::FindPreferredIcon(
310              app_info.document_icons, drive::util::kPreferredIconSize);
311          properties_->custom_icon_url.reset(new std::string(doc_icon.spec()));
312        }
313      }
314    }
315
316    file_system->GetCacheEntry(
317        file_path_,
318        base::Bind(&SingleDriveEntryPropertiesGetter::CacheStateReceived,
319                   GetWeakPtr()));
320  }
321
322  void CacheStateReceived(bool /* success */,
323                          const drive::FileCacheEntry& cache_entry) {
324    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
325
326    // In case of an error (i.e. success is false), cache_entry.is_*() all
327    // returns false.
328    properties_->is_pinned.reset(new bool(cache_entry.is_pinned()));
329    properties_->is_present.reset(new bool(cache_entry.is_present()));
330
331    CompleteGetFileProperties(drive::FILE_ERROR_OK);
332  }
333
334  void CompleteGetFileProperties(drive::FileError error) {
335    DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
336    DCHECK(!callback_.is_null());
337    callback_.Run(error);
338
339    delete this;
340  }
341};  // class SingleDriveEntryPropertiesGetter
342
343}  // namespace
344
345FileBrowserPrivateGetDriveEntryPropertiesFunction::
346    FileBrowserPrivateGetDriveEntryPropertiesFunction()
347    : processed_count_(0) {}
348
349FileBrowserPrivateGetDriveEntryPropertiesFunction::
350    ~FileBrowserPrivateGetDriveEntryPropertiesFunction() {}
351
352bool FileBrowserPrivateGetDriveEntryPropertiesFunction::RunAsync() {
353  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
354
355  using api::file_browser_private::GetDriveEntryProperties::Params;
356  const scoped_ptr<Params> params(Params::Create(*args_));
357  EXTENSION_FUNCTION_VALIDATE(params);
358
359  properties_list_.resize(params->file_urls.size());
360
361  for (size_t i = 0; i < params->file_urls.size(); i++) {
362    const GURL url = GURL(params->file_urls[i]);
363    const base::FilePath local_path = file_manager::util::GetLocalPathFromURL(
364        render_view_host(), GetProfile(), url);
365    properties_list_[i] = make_linked_ptr(new DriveEntryProperties);
366
367    SingleDriveEntryPropertiesGetter::Start(
368        local_path,
369        properties_list_[i],
370        GetProfile(),
371        base::Bind(&FileBrowserPrivateGetDriveEntryPropertiesFunction::
372                       CompleteGetFileProperties,
373                   this));
374  }
375
376  return true;
377}
378
379void FileBrowserPrivateGetDriveEntryPropertiesFunction::
380    CompleteGetFileProperties(drive::FileError error) {
381  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
382  DCHECK(0 <= processed_count_ && processed_count_ < properties_list_.size());
383
384  processed_count_++;
385  if (processed_count_ < properties_list_.size())
386    return;
387
388  results_ = extensions::api::file_browser_private::GetDriveEntryProperties::
389      Results::Create(properties_list_);
390  SendResponse(true);
391}
392
393bool FileBrowserPrivatePinDriveFileFunction::RunAsync() {
394  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
395
396  using extensions::api::file_browser_private::PinDriveFile::Params;
397  const scoped_ptr<Params> params(Params::Create(*args_));
398  EXTENSION_FUNCTION_VALIDATE(params);
399
400  drive::FileSystemInterface* const file_system =
401      drive::util::GetFileSystemByProfile(GetProfile());
402  if (!file_system)  // |file_system| is NULL if Drive is disabled.
403    return false;
404
405  const base::FilePath drive_path =
406      drive::util::ExtractDrivePath(file_manager::util::GetLocalPathFromURL(
407          render_view_host(), GetProfile(), GURL(params->file_url)));
408  if (params->pin) {
409    file_system->Pin(drive_path,
410                     base::Bind(&FileBrowserPrivatePinDriveFileFunction::
411                                    OnPinStateSet, this));
412  } else {
413    file_system->Unpin(drive_path,
414                       base::Bind(&FileBrowserPrivatePinDriveFileFunction::
415                                      OnPinStateSet, this));
416  }
417  return true;
418}
419
420void FileBrowserPrivatePinDriveFileFunction::
421    OnPinStateSet(drive::FileError error) {
422  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
423
424  if (error == drive::FILE_ERROR_OK) {
425    SendResponse(true);
426  } else {
427    SetError(drive::FileErrorToString(error));
428    SendResponse(false);
429  }
430}
431
432FileBrowserPrivateGetDriveFilesFunction::
433    FileBrowserPrivateGetDriveFilesFunction() {
434}
435
436FileBrowserPrivateGetDriveFilesFunction::
437    ~FileBrowserPrivateGetDriveFilesFunction() {
438}
439
440bool FileBrowserPrivateGetDriveFilesFunction::RunAsync() {
441  using extensions::api::file_browser_private::GetDriveFiles::Params;
442  const scoped_ptr<Params> params(Params::Create(*args_));
443  EXTENSION_FUNCTION_VALIDATE(params);
444
445  // Convert the list of strings to a list of GURLs.
446  for (size_t i = 0; i < params->file_urls.size(); ++i) {
447    const base::FilePath path = file_manager::util::GetLocalPathFromURL(
448        render_view_host(), GetProfile(), GURL(params->file_urls[i]));
449    DCHECK(drive::util::IsUnderDriveMountPoint(path));
450    base::FilePath drive_path = drive::util::ExtractDrivePath(path);
451    remaining_drive_paths_.push(drive_path);
452  }
453
454  GetFileOrSendResponse();
455  return true;
456}
457
458void FileBrowserPrivateGetDriveFilesFunction::GetFileOrSendResponse() {
459  // Send the response if all files are obtained.
460  if (remaining_drive_paths_.empty()) {
461    results_ = extensions::api::file_browser_private::
462        GetDriveFiles::Results::Create(local_paths_);
463    SendResponse(true);
464    return;
465  }
466
467  // Get the file on the top of the queue.
468  base::FilePath drive_path = remaining_drive_paths_.front();
469
470  drive::FileSystemInterface* file_system =
471      drive::util::GetFileSystemByProfile(GetProfile());
472  if (!file_system) {
473    // |file_system| is NULL if Drive is disabled or not mounted.
474    OnFileReady(drive::FILE_ERROR_FAILED, drive_path,
475                scoped_ptr<drive::ResourceEntry>());
476    return;
477  }
478
479  file_system->GetFile(
480      drive_path,
481      base::Bind(&FileBrowserPrivateGetDriveFilesFunction::OnFileReady, this));
482}
483
484
485void FileBrowserPrivateGetDriveFilesFunction::OnFileReady(
486    drive::FileError error,
487    const base::FilePath& local_path,
488    scoped_ptr<drive::ResourceEntry> entry) {
489  base::FilePath drive_path = remaining_drive_paths_.front();
490
491  if (error == drive::FILE_ERROR_OK) {
492    local_paths_.push_back(local_path.AsUTF8Unsafe());
493    DVLOG(1) << "Got " << drive_path.value() << " as " << local_path.value();
494  } else {
495    local_paths_.push_back("");
496    DVLOG(1) << "Failed to get " << drive_path.value()
497             << " with error code: " << error;
498  }
499
500  remaining_drive_paths_.pop();
501
502  // Start getting the next file.
503  GetFileOrSendResponse();
504}
505
506bool FileBrowserPrivateCancelFileTransfersFunction::RunAsync() {
507  using extensions::api::file_browser_private::CancelFileTransfers::Params;
508  const scoped_ptr<Params> params(Params::Create(*args_));
509  EXTENSION_FUNCTION_VALIDATE(params);
510
511  drive::DriveIntegrationService* integration_service =
512      drive::DriveIntegrationServiceFactory::FindForProfile(GetProfile());
513  if (!integration_service || !integration_service->IsMounted())
514    return false;
515
516  // Create the mapping from file path to job ID.
517  drive::JobListInterface* job_list = integration_service->job_list();
518  DCHECK(job_list);
519  std::vector<drive::JobInfo> jobs = job_list->GetJobInfoList();
520
521  typedef std::map<base::FilePath, std::vector<drive::JobID> > PathToIdMap;
522  PathToIdMap path_to_id_map;
523  for (size_t i = 0; i < jobs.size(); ++i) {
524    if (drive::IsActiveFileTransferJobInfo(jobs[i]))
525      path_to_id_map[jobs[i].file_path].push_back(jobs[i].job_id);
526  }
527
528  // Cancel by Job ID.
529  std::vector<linked_ptr<api::file_browser_private::
530                         FileTransferCancelStatus> > responses;
531  for (size_t i = 0; i < params->file_urls.size(); ++i) {
532    base::FilePath file_path = file_manager::util::GetLocalPathFromURL(
533        render_view_host(), GetProfile(), GURL(params->file_urls[i]));
534    if (file_path.empty())
535      continue;
536
537    DCHECK(drive::util::IsUnderDriveMountPoint(file_path));
538    file_path = drive::util::ExtractDrivePath(file_path);
539
540    // Cancel all the jobs for the file.
541    PathToIdMap::iterator it = path_to_id_map.find(file_path);
542    if (it != path_to_id_map.end()) {
543      for (size_t i = 0; i < it->second.size(); ++i)
544        job_list->CancelJob(it->second[i]);
545    }
546    linked_ptr<api::file_browser_private::FileTransferCancelStatus> result(
547        new api::file_browser_private::FileTransferCancelStatus);
548    result->canceled = it != path_to_id_map.end();
549    // TODO(kinaba): simplify cancelFileTransfer() to take single URL each time,
550    // and eliminate this field; it is just returning a copy of the argument.
551    result->file_url = params->file_urls[i];
552    responses.push_back(result);
553  }
554  results_ = api::file_browser_private::CancelFileTransfers::Results::Create(
555      responses);
556  SendResponse(true);
557  return true;
558}
559
560bool FileBrowserPrivateSearchDriveFunction::RunAsync() {
561  using extensions::api::file_browser_private::SearchDrive::Params;
562  const scoped_ptr<Params> params(Params::Create(*args_));
563  EXTENSION_FUNCTION_VALIDATE(params);
564
565  drive::FileSystemInterface* const file_system =
566      drive::util::GetFileSystemByProfile(GetProfile());
567  if (!file_system) {
568    // |file_system| is NULL if Drive is disabled.
569    return false;
570  }
571
572  file_system->Search(
573      params->search_params.query, GURL(params->search_params.next_feed),
574      base::Bind(&FileBrowserPrivateSearchDriveFunction::OnSearch, this));
575  return true;
576}
577
578void FileBrowserPrivateSearchDriveFunction::OnSearch(
579    drive::FileError error,
580    const GURL& next_link,
581    scoped_ptr<SearchResultInfoList> results) {
582  if (error != drive::FILE_ERROR_OK) {
583    SendResponse(false);
584    return;
585  }
586
587  // Outlives the following conversion, since the pointer is bound to the
588  // callback.
589  DCHECK(results.get());
590  const SearchResultInfoList& results_ref = *results.get();
591
592  ConvertSearchResultInfoListToEntryDefinitionList(
593      GetProfile(),
594      extension_->id(),
595      results_ref,
596      base::Bind(&FileBrowserPrivateSearchDriveFunction::OnEntryDefinitionList,
597                 this,
598                 next_link,
599                 base::Passed(&results)));
600}
601
602void FileBrowserPrivateSearchDriveFunction::OnEntryDefinitionList(
603    const GURL& next_link,
604    scoped_ptr<SearchResultInfoList> search_result_info_list,
605    scoped_ptr<EntryDefinitionList> entry_definition_list) {
606  DCHECK_EQ(search_result_info_list->size(), entry_definition_list->size());
607  base::ListValue* entries = new base::ListValue();
608
609  // Convert Drive files to something File API stack can understand.
610  for (EntryDefinitionList::const_iterator it = entry_definition_list->begin();
611       it != entry_definition_list->end();
612       ++it) {
613    base::DictionaryValue* entry = new base::DictionaryValue();
614    entry->SetString("fileSystemName", it->file_system_name);
615    entry->SetString("fileSystemRoot", it->file_system_root_url);
616    entry->SetString("fileFullPath", "/" + it->full_path.AsUTF8Unsafe());
617    entry->SetBoolean("fileIsDirectory", it->is_directory);
618    entries->Append(entry);
619  }
620
621  base::DictionaryValue* result = new base::DictionaryValue();
622  result->Set("entries", entries);
623  result->SetString("nextFeed", next_link.spec());
624
625  SetResult(result);
626  SendResponse(true);
627}
628
629bool FileBrowserPrivateSearchDriveMetadataFunction::RunAsync() {
630  using api::file_browser_private::SearchDriveMetadata::Params;
631  const scoped_ptr<Params> params(Params::Create(*args_));
632  EXTENSION_FUNCTION_VALIDATE(params);
633
634  drive::EventLogger* logger = file_manager::util::GetLogger(GetProfile());
635  if (logger) {
636    logger->Log(logging::LOG_INFO,
637                "%s[%d] called. (types: '%s', maxResults: '%d')",
638                name().c_str(),
639                request_id(),
640                api::file_browser_private::ToString(
641                    params->search_params.types).c_str(),
642                params->search_params.max_results);
643  }
644  set_log_on_completion(true);
645
646  drive::FileSystemInterface* const file_system =
647      drive::util::GetFileSystemByProfile(GetProfile());
648  if (!file_system) {
649    // |file_system| is NULL if Drive is disabled.
650    return false;
651  }
652
653  int options = -1;
654  switch (params->search_params.types) {
655    case api::file_browser_private::SEARCH_TYPE_EXCLUDE_DIRECTORIES:
656      options = drive::SEARCH_METADATA_EXCLUDE_DIRECTORIES;
657      break;
658    case api::file_browser_private::SEARCH_TYPE_SHARED_WITH_ME:
659      options = drive::SEARCH_METADATA_SHARED_WITH_ME;
660      break;
661    case api::file_browser_private::SEARCH_TYPE_OFFLINE:
662      options = drive::SEARCH_METADATA_OFFLINE;
663      break;
664    case api::file_browser_private::SEARCH_TYPE_ALL:
665      options = drive::SEARCH_METADATA_ALL;
666      break;
667    case api::file_browser_private::SEARCH_TYPE_NONE:
668      break;
669  }
670  DCHECK_NE(options, -1);
671
672  file_system->SearchMetadata(
673      params->search_params.query,
674      options,
675      params->search_params.max_results,
676      base::Bind(&FileBrowserPrivateSearchDriveMetadataFunction::
677                     OnSearchMetadata, this));
678  return true;
679}
680
681void FileBrowserPrivateSearchDriveMetadataFunction::OnSearchMetadata(
682    drive::FileError error,
683    scoped_ptr<drive::MetadataSearchResultVector> results) {
684  if (error != drive::FILE_ERROR_OK) {
685    SendResponse(false);
686    return;
687  }
688
689  // Outlives the following conversion, since the pointer is bound to the
690  // callback.
691  DCHECK(results.get());
692  const drive::MetadataSearchResultVector& results_ref = *results.get();
693
694  ConvertSearchResultInfoListToEntryDefinitionList(
695      GetProfile(),
696      extension_->id(),
697      results_ref,
698      base::Bind(
699          &FileBrowserPrivateSearchDriveMetadataFunction::OnEntryDefinitionList,
700          this,
701          base::Passed(&results)));
702}
703
704void FileBrowserPrivateSearchDriveMetadataFunction::OnEntryDefinitionList(
705    scoped_ptr<drive::MetadataSearchResultVector> search_result_info_list,
706    scoped_ptr<EntryDefinitionList> entry_definition_list) {
707  DCHECK_EQ(search_result_info_list->size(), entry_definition_list->size());
708  base::ListValue* results_list = new base::ListValue();
709
710  // Convert Drive files to something File API stack can understand.  See
711  // file_browser_handler_custom_bindings.cc and
712  // file_browser_private_custom_bindings.js for how this is magically
713  // converted to a FileEntry.
714  for (size_t i = 0; i < entry_definition_list->size(); ++i) {
715    base::DictionaryValue* result_dict = new base::DictionaryValue();
716
717    // FileEntry fields.
718    base::DictionaryValue* entry = new base::DictionaryValue();
719    entry->SetString(
720        "fileSystemName", entry_definition_list->at(i).file_system_name);
721    entry->SetString(
722        "fileSystemRoot", entry_definition_list->at(i).file_system_root_url);
723    entry->SetString(
724        "fileFullPath",
725        "/" + entry_definition_list->at(i).full_path.AsUTF8Unsafe());
726    entry->SetBoolean("fileIsDirectory",
727                      entry_definition_list->at(i).is_directory);
728
729    result_dict->Set("entry", entry);
730    result_dict->SetString(
731        "highlightedBaseName",
732        search_result_info_list->at(i).highlighted_base_name);
733    results_list->Append(result_dict);
734  }
735
736  SetResult(results_list);
737  SendResponse(true);
738}
739
740bool FileBrowserPrivateGetDriveConnectionStateFunction::RunSync() {
741  api::file_browser_private::DriveConnectionState result;
742
743  switch (drive::util::GetDriveConnectionStatus(GetProfile())) {
744    case drive::util::DRIVE_DISCONNECTED_NOSERVICE:
745      result.type = kDriveConnectionTypeOffline;
746      result.reason.reset(new std::string(kDriveConnectionReasonNoService));
747      break;
748    case drive::util::DRIVE_DISCONNECTED_NONETWORK:
749      result.type = kDriveConnectionTypeOffline;
750      result.reason.reset(new std::string(kDriveConnectionReasonNoNetwork));
751      break;
752    case drive::util::DRIVE_DISCONNECTED_NOTREADY:
753      result.type = kDriveConnectionTypeOffline;
754      result.reason.reset(new std::string(kDriveConnectionReasonNotReady));
755      break;
756    case drive::util::DRIVE_CONNECTED_METERED:
757      result.type = kDriveConnectionTypeMetered;
758      break;
759    case drive::util::DRIVE_CONNECTED:
760      result.type = kDriveConnectionTypeOnline;
761      break;
762  }
763
764  results_ = api::file_browser_private::GetDriveConnectionState::Results::
765      Create(result);
766
767  drive::EventLogger* logger = file_manager::util::GetLogger(GetProfile());
768  if (logger)
769    logger->Log(logging::LOG_INFO, "%s succeeded.", name().c_str());
770  return true;
771}
772
773bool FileBrowserPrivateRequestAccessTokenFunction::RunAsync() {
774  using extensions::api::file_browser_private::RequestAccessToken::Params;
775  const scoped_ptr<Params> params(Params::Create(*args_));
776  EXTENSION_FUNCTION_VALIDATE(params);
777
778  drive::DriveServiceInterface* const drive_service =
779      drive::util::GetDriveServiceByProfile(GetProfile());
780
781  if (!drive_service) {
782    // DriveService is not available.
783    SetResult(new base::StringValue(""));
784    SendResponse(true);
785    return true;
786  }
787
788  // If refreshing is requested, then clear the token to refetch it.
789  if (params->refresh)
790    drive_service->ClearAccessToken();
791
792  // Retrieve the cached auth token (if available), otherwise the AuthService
793  // instance will try to refetch it.
794  drive_service->RequestAccessToken(
795      base::Bind(&FileBrowserPrivateRequestAccessTokenFunction::
796                      OnAccessTokenFetched, this));
797  return true;
798}
799
800void FileBrowserPrivateRequestAccessTokenFunction::OnAccessTokenFetched(
801    google_apis::GDataErrorCode code,
802    const std::string& access_token) {
803  SetResult(new base::StringValue(access_token));
804  SendResponse(true);
805}
806
807bool FileBrowserPrivateGetShareUrlFunction::RunAsync() {
808  using extensions::api::file_browser_private::GetShareUrl::Params;
809  const scoped_ptr<Params> params(Params::Create(*args_));
810  EXTENSION_FUNCTION_VALIDATE(params);
811
812  const base::FilePath path = file_manager::util::GetLocalPathFromURL(
813      render_view_host(), GetProfile(), GURL(params->url));
814  DCHECK(drive::util::IsUnderDriveMountPoint(path));
815
816  const base::FilePath drive_path = drive::util::ExtractDrivePath(path);
817
818  drive::FileSystemInterface* const file_system =
819      drive::util::GetFileSystemByProfile(GetProfile());
820  if (!file_system) {
821    // |file_system| is NULL if Drive is disabled.
822    return false;
823  }
824
825  file_system->GetShareUrl(
826      drive_path,
827      file_manager::util::GetFileManagerBaseUrl(),  // embed origin
828      base::Bind(&FileBrowserPrivateGetShareUrlFunction::OnGetShareUrl, this));
829  return true;
830}
831
832void FileBrowserPrivateGetShareUrlFunction::OnGetShareUrl(
833    drive::FileError error,
834    const GURL& share_url) {
835  if (error != drive::FILE_ERROR_OK) {
836    SetError("Share Url for this item is not available.");
837    SendResponse(false);
838    return;
839  }
840
841  SetResult(new base::StringValue(share_url.spec()));
842  SendResponse(true);
843}
844
845bool FileBrowserPrivateRequestDriveShareFunction::RunAsync() {
846  using extensions::api::file_browser_private::RequestDriveShare::Params;
847  const scoped_ptr<Params> params(Params::Create(*args_));
848  EXTENSION_FUNCTION_VALIDATE(params);
849
850  const base::FilePath path = file_manager::util::GetLocalPathFromURL(
851      render_view_host(), GetProfile(), GURL(params->url));
852  const base::FilePath drive_path = drive::util::ExtractDrivePath(path);
853  Profile* const owner_profile = drive::util::ExtractProfileFromPath(path);
854
855  if (!owner_profile)
856    return false;
857
858  drive::FileSystemInterface* const owner_file_system =
859      drive::util::GetFileSystemByProfile(owner_profile);
860  if (!owner_file_system)
861    return false;
862
863  const chromeos::User* const user =
864      chromeos::UserManager::Get()->GetUserByProfile(GetProfile());
865  if (!user || !user->is_logged_in())
866    return false;
867
868  google_apis::drive::PermissionRole role =
869      google_apis::drive::PERMISSION_ROLE_READER;
870  switch (params->share_type) {
871    case api::file_browser_private::DRIVE_SHARE_TYPE_NONE:
872      NOTREACHED();
873      return false;
874    case api::file_browser_private::DRIVE_SHARE_TYPE_CAN_EDIT:
875      role = google_apis::drive::PERMISSION_ROLE_WRITER;
876      break;
877    case api::file_browser_private::DRIVE_SHARE_TYPE_CAN_COMMENT:
878      role = google_apis::drive::PERMISSION_ROLE_COMMENTER;
879      break;
880    case api::file_browser_private::DRIVE_SHARE_TYPE_CAN_VIEW:
881      role = google_apis::drive::PERMISSION_ROLE_READER;
882      break;
883  }
884
885  // Share |drive_path| in |owner_file_system| to |user->email()|.
886  owner_file_system->AddPermission(
887      drive_path,
888      user->email(),
889      role,
890      base::Bind(&FileBrowserPrivateRequestDriveShareFunction::OnAddPermission,
891                 this));
892  return true;
893}
894
895void FileBrowserPrivateRequestDriveShareFunction::OnAddPermission(
896    drive::FileError error) {
897  SendResponse(error == drive::FILE_ERROR_OK);
898}
899
900}  // namespace extensions
901