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