private_api_drive.cc revision 3551c9c881056c480085172ff9840cab31610854
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 "base/prefs/pref_service.h"
8#include "base/strings/stringprintf.h"
9#include "chrome/browser/chromeos/drive/drive_app_registry.h"
10#include "chrome/browser/chromeos/drive/drive_integration_service.h"
11#include "chrome/browser/chromeos/drive/logging.h"
12#include "chrome/browser/chromeos/extensions/file_manager/file_tasks.h"
13#include "chrome/browser/chromeos/extensions/file_manager/private_api_util.h"
14#include "chrome/browser/chromeos/extensions/file_manager/url_util.h"
15#include "chrome/browser/chromeos/fileapi/file_system_backend.h"
16#include "chrome/browser/extensions/api/file_handlers/app_file_handler_util.h"
17#include "chrome/browser/profiles/profile.h"
18#include "chrome/common/pref_names.h"
19#include "content/public/browser/browser_thread.h"
20#include "content/public/browser/render_view_host.h"
21#include "webkit/common/fileapi/file_system_util.h"
22
23using content::BrowserThread;
24
25namespace file_manager {
26namespace {
27
28// List of connection types of drive.
29// Keep this in sync with the DriveConnectionType in volume_manager.js.
30const char kDriveConnectionTypeOffline[] = "offline";
31const char kDriveConnectionTypeMetered[] = "metered";
32const char kDriveConnectionTypeOnline[] = "online";
33
34
35// List of reasons of kDriveConnectionType*.
36// Keep this in sync with the DriveConnectionReason in volume_manager.js.
37const char kDriveConnectionReasonNotReady[] = "not_ready";
38const char kDriveConnectionReasonNoNetwork[] = "no_network";
39const char kDriveConnectionReasonNoService[] = "no_service";
40
41// Does nothing with a bool parameter. Used as a placeholder for calling
42// ClearCacheAndRemountFileSystem(). TODO(yoshiki): Handle an error from
43// ClearCacheAndRemountFileSystem() properly: http://crbug.com/140511.
44void DoNothingWithBool(bool /* success */) {
45}
46
47// Copies properties from |entry_proto| to |property_dict|.
48void FillDriveEntryPropertiesValue(
49    const drive::ResourceEntry& entry_proto,
50    DictionaryValue* property_dict) {
51  property_dict->SetBoolean("sharedWithMe", entry_proto.shared_with_me());
52
53  if (!entry_proto.has_file_specific_info())
54    return;
55
56  const drive::FileSpecificInfo& file_specific_info =
57      entry_proto.file_specific_info();
58
59  property_dict->SetString("thumbnailUrl", file_specific_info.thumbnail_url());
60  property_dict->SetBoolean("isHosted",
61                            file_specific_info.is_hosted_document());
62  property_dict->SetString("contentMimeType",
63                           file_specific_info.content_mime_type());
64}
65
66}  // namespace
67
68GetDriveEntryPropertiesFunction::GetDriveEntryPropertiesFunction() {
69}
70
71GetDriveEntryPropertiesFunction::~GetDriveEntryPropertiesFunction() {
72}
73
74bool GetDriveEntryPropertiesFunction::RunImpl() {
75  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
76
77  std::string file_url_str;
78  if (args_->GetSize() != 1 || !args_->GetString(0, &file_url_str))
79    return false;
80
81  GURL file_url = GURL(file_url_str);
82  file_path_ = drive::util::ExtractDrivePath(
83      util::GetLocalPathFromURL(render_view_host(), profile(), file_url));
84
85  properties_.reset(new base::DictionaryValue);
86  properties_->SetString("fileUrl", file_url.spec());
87
88  // Start getting the file info.
89  drive::DriveIntegrationService* integration_service =
90      drive::DriveIntegrationServiceFactory::GetForProfile(profile_);
91  // |integration_service| is NULL if Drive is disabled.
92  if (!integration_service) {
93    CompleteGetFileProperties(drive::FILE_ERROR_FAILED);
94    return true;
95  }
96
97  integration_service->file_system()->GetResourceEntryByPath(
98      file_path_,
99      base::Bind(&GetDriveEntryPropertiesFunction::OnGetFileInfo, this));
100  return true;
101}
102
103void GetDriveEntryPropertiesFunction::OnGetFileInfo(
104    drive::FileError error,
105    scoped_ptr<drive::ResourceEntry> entry) {
106  DCHECK(properties_);
107
108  if (error != drive::FILE_ERROR_OK) {
109    CompleteGetFileProperties(error);
110    return;
111  }
112  DCHECK(entry);
113
114  FillDriveEntryPropertiesValue(*entry, properties_.get());
115
116  drive::DriveIntegrationService* integration_service =
117      drive::DriveIntegrationServiceFactory::GetForProfile(profile_);
118  // |integration_service| is NULL if Drive is disabled.
119  if (!integration_service) {
120    CompleteGetFileProperties(drive::FILE_ERROR_FAILED);
121    return;
122  }
123
124  // The properties meaningful for directories are already filled in
125  // FillDriveEntryPropertiesValue().
126  if (entry.get() && !entry->has_file_specific_info()) {
127    CompleteGetFileProperties(error);
128    return;
129  }
130
131  const drive::FileSpecificInfo& file_specific_info =
132      entry->file_specific_info();
133
134  // Get drive WebApps that can accept this file.
135  ScopedVector<drive::DriveAppInfo> drive_apps;
136  integration_service->drive_app_registry()->GetAppsForFile(
137      file_path_, file_specific_info.content_mime_type(), &drive_apps);
138  if (!drive_apps.empty()) {
139    std::string default_task_id = file_tasks::GetDefaultTaskIdFromPrefs(
140        profile_,
141        file_specific_info.content_mime_type(),
142        file_path_.Extension());
143    file_tasks::TaskDescriptor default_task;
144    file_tasks::ParseTaskID(default_task_id, &default_task);
145    DCHECK(default_task_id.empty() || !default_task.app_id.empty());
146
147    ListValue* apps = new ListValue();
148    properties_->Set("driveApps", apps);
149    for (ScopedVector<drive::DriveAppInfo>::const_iterator it =
150             drive_apps.begin();
151         it != drive_apps.end(); ++it) {
152      const drive::DriveAppInfo* app_info = *it;
153      DictionaryValue* app = new DictionaryValue();
154      app->SetString("appId", app_info->app_id);
155      app->SetString("appName", app_info->app_name);
156      GURL app_icon = util::FindPreferredIcon(app_info->app_icons,
157                                              util::kPreferredIconSize);
158      if (!app_icon.is_empty())
159        app->SetString("appIcon", app_icon.spec());
160      GURL doc_icon = util::FindPreferredIcon(app_info->document_icons,
161                                              util::kPreferredIconSize);
162      if (!doc_icon.is_empty())
163        app->SetString("docIcon", doc_icon.spec());
164      app->SetString("objectType", app_info->object_type);
165      app->SetBoolean("isPrimary",
166                      default_task.app_id == app_info->app_id);
167      apps->Append(app);
168    }
169  }
170
171  integration_service->file_system()->GetCacheEntryByResourceId(
172      entry->resource_id(),
173      base::Bind(&GetDriveEntryPropertiesFunction::CacheStateReceived, this));
174}
175
176void GetDriveEntryPropertiesFunction::CacheStateReceived(
177    bool /* success */,
178    const drive::FileCacheEntry& cache_entry) {
179  // In case of an error (i.e. success is false), cache_entry.is_*() all
180  // returns false.
181  properties_->SetBoolean("isPinned", cache_entry.is_pinned());
182  properties_->SetBoolean("isPresent", cache_entry.is_present());
183  properties_->SetBoolean("isDirty", cache_entry.is_dirty());
184
185  CompleteGetFileProperties(drive::FILE_ERROR_OK);
186}
187
188void GetDriveEntryPropertiesFunction::CompleteGetFileProperties(
189    drive::FileError error) {
190  if (error != drive::FILE_ERROR_OK)
191    properties_->SetInteger("errorCode", error);
192  SetResult(properties_.release());
193  SendResponse(true);
194}
195
196PinDriveFileFunction::PinDriveFileFunction() {
197}
198
199PinDriveFileFunction::~PinDriveFileFunction() {
200}
201
202bool PinDriveFileFunction::RunImpl() {
203  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
204  std::string url;
205  bool set_pin = false;
206  if (args_->GetSize() != 2 ||
207      !args_->GetString(0, &url) ||
208      !args_->GetBoolean(1, &set_pin))
209    return false;
210
211  drive::DriveIntegrationService* integration_service =
212      drive::DriveIntegrationServiceFactory::GetForProfile(profile_);
213  drive::FileSystemInterface* file_system =
214      integration_service ? integration_service->file_system() : NULL;
215  if (!file_system)  // |file_system| is NULL if Drive is disabled.
216    return false;
217
218  base::FilePath drive_path =
219      drive::util::ExtractDrivePath(
220          util::GetLocalPathFromURL(render_view_host(), profile(), GURL(url)));
221  if (set_pin) {
222    file_system->Pin(drive_path,
223                     base::Bind(&PinDriveFileFunction::OnPinStateSet, this));
224  } else {
225    file_system->Unpin(drive_path,
226                       base::Bind(&PinDriveFileFunction::OnPinStateSet, this));
227  }
228  return true;
229}
230
231void PinDriveFileFunction::OnPinStateSet(drive::FileError error) {
232  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
233
234  if (error == drive::FILE_ERROR_OK) {
235    SendResponse(true);
236  } else {
237    error_ = drive::FileErrorToString(error);
238    SendResponse(false);
239  }
240}
241
242GetDriveFilesFunction::GetDriveFilesFunction()
243    : local_paths_(NULL) {
244}
245
246GetDriveFilesFunction::~GetDriveFilesFunction() {
247}
248
249bool GetDriveFilesFunction::RunImpl() {
250  ListValue* file_urls_as_strings = NULL;
251  if (!args_->GetList(0, &file_urls_as_strings))
252    return false;
253
254  // Convert the list of strings to a list of GURLs.
255  for (size_t i = 0; i < file_urls_as_strings->GetSize(); ++i) {
256    std::string file_url_as_string;
257    if (!file_urls_as_strings->GetString(i, &file_url_as_string))
258      return false;
259    const base::FilePath path = util::GetLocalPathFromURL(
260        render_view_host(), profile(), GURL(file_url_as_string));
261    DCHECK(drive::util::IsUnderDriveMountPoint(path));
262    base::FilePath drive_path = drive::util::ExtractDrivePath(path);
263    remaining_drive_paths_.push(drive_path);
264  }
265
266  local_paths_ = new ListValue;
267  GetFileOrSendResponse();
268  return true;
269}
270
271void GetDriveFilesFunction::GetFileOrSendResponse() {
272  // Send the response if all files are obtained.
273  if (remaining_drive_paths_.empty()) {
274    SetResult(local_paths_);
275    SendResponse(true);
276    return;
277  }
278
279  // Get the file on the top of the queue.
280  base::FilePath drive_path = remaining_drive_paths_.front();
281
282  drive::DriveIntegrationService* integration_service =
283      drive::DriveIntegrationServiceFactory::GetForProfile(profile_);
284  // |integration_service| is NULL if Drive is disabled.
285  if (!integration_service) {
286    OnFileReady(drive::FILE_ERROR_FAILED, drive_path,
287                scoped_ptr<drive::ResourceEntry>());
288    return;
289  }
290
291  integration_service->file_system()->GetFileByPath(
292      drive_path,
293      base::Bind(&GetDriveFilesFunction::OnFileReady, this));
294}
295
296
297void GetDriveFilesFunction::OnFileReady(
298    drive::FileError error,
299    const base::FilePath& local_path,
300    scoped_ptr<drive::ResourceEntry> entry) {
301  base::FilePath drive_path = remaining_drive_paths_.front();
302
303  if (error == drive::FILE_ERROR_OK) {
304    local_paths_->Append(new base::StringValue(local_path.value()));
305    DVLOG(1) << "Got " << drive_path.value() << " as " << local_path.value();
306
307    // TODO(benchan): If the file is a hosted document, a temporary JSON file
308    // is created to represent the document. The JSON file is not cached and
309    // should be deleted after use. We need to somehow communicate with
310    // file_manager.js to manage the lifetime of the temporary file.
311    // See crosbug.com/28058.
312  } else {
313    local_paths_->Append(new base::StringValue(""));
314    DVLOG(1) << "Failed to get " << drive_path.value()
315             << " with error code: " << error;
316  }
317
318  remaining_drive_paths_.pop();
319
320  // Start getting the next file.
321  GetFileOrSendResponse();
322}
323
324CancelFileTransfersFunction::CancelFileTransfersFunction() {
325}
326
327CancelFileTransfersFunction::~CancelFileTransfersFunction() {
328}
329
330bool CancelFileTransfersFunction::RunImpl() {
331  ListValue* url_list = NULL;
332  if (!args_->GetList(0, &url_list))
333    return false;
334
335  drive::DriveIntegrationService* integration_service =
336      drive::DriveIntegrationServiceFactory::GetForProfile(profile_);
337  // |integration_service| is NULL if Drive is disabled.
338  if (!integration_service)
339    return false;
340
341  // Create the mapping from file path to job ID.
342  drive::JobListInterface* job_list = integration_service->job_list();
343  DCHECK(job_list);
344  std::vector<drive::JobInfo> jobs = job_list->GetJobInfoList();
345
346  typedef std::map<base::FilePath, std::vector<drive::JobID> > PathToIdMap;
347  PathToIdMap path_to_id_map;
348  for (size_t i = 0; i < jobs.size(); ++i) {
349    if (drive::IsActiveFileTransferJobInfo(jobs[i]))
350      path_to_id_map[jobs[i].file_path].push_back(jobs[i].job_id);
351  }
352
353  // Cancel by Job ID.
354  scoped_ptr<ListValue> responses(new ListValue());
355  for (size_t i = 0; i < url_list->GetSize(); ++i) {
356    std::string url_as_string;
357    url_list->GetString(i, &url_as_string);
358
359    base::FilePath file_path = util::GetLocalPathFromURL(
360        render_view_host(), profile(), GURL(url_as_string));
361    if (file_path.empty())
362      continue;
363
364    DCHECK(drive::util::IsUnderDriveMountPoint(file_path));
365    file_path = drive::util::ExtractDrivePath(file_path);
366    scoped_ptr<DictionaryValue> result(new DictionaryValue());
367
368    // Cancel all the jobs for the file.
369    PathToIdMap::iterator it = path_to_id_map.find(file_path);
370    if (it != path_to_id_map.end()) {
371      for (size_t i = 0; i < it->second.size(); ++i)
372        job_list->CancelJob(it->second[i]);
373    }
374    result->SetBoolean("canceled", it != path_to_id_map.end());
375    // TODO(kinaba): simplify cancelFileTransfer() to take single URL each time,
376    // and eliminate this field; it is just returning a copy of the argument.
377    result->SetString("fileUrl", url_as_string);
378    responses->Append(result.release());
379  }
380  SetResult(responses.release());
381  SendResponse(true);
382  return true;
383}
384
385SearchDriveFunction::SearchDriveFunction() {
386}
387
388SearchDriveFunction::~SearchDriveFunction() {
389}
390
391bool SearchDriveFunction::RunImpl() {
392  DictionaryValue* search_params;
393  if (!args_->GetDictionary(0, &search_params))
394    return false;
395
396  std::string query;
397  if (!search_params->GetString("query", &query))
398    return false;
399
400  std::string next_feed;
401  if (!search_params->GetString("nextFeed", &next_feed))
402    return false;
403
404  drive::DriveIntegrationService* integration_service =
405      drive::DriveIntegrationServiceFactory::GetForProfile(profile_);
406  // |integration_service| is NULL if Drive is disabled.
407  if (!integration_service || !integration_service->file_system())
408    return false;
409
410  integration_service->file_system()->Search(
411      query, GURL(next_feed),
412      base::Bind(&SearchDriveFunction::OnSearch, this));
413  return true;
414}
415
416void SearchDriveFunction::OnSearch(
417    drive::FileError error,
418    const GURL& next_feed,
419    scoped_ptr<std::vector<drive::SearchResultInfo> > results) {
420  if (error != drive::FILE_ERROR_OK) {
421    SendResponse(false);
422    return;
423  }
424
425  DCHECK(results.get());
426
427  base::ListValue* entries = new ListValue();
428
429  // Convert Drive files to something File API stack can understand.
430  GURL origin_url = source_url_.GetOrigin();
431  fileapi::FileSystemType file_system_type = fileapi::kFileSystemTypeExternal;
432  GURL file_system_root_url =
433      fileapi::GetFileSystemRootURI(origin_url, file_system_type);
434  std::string file_system_name =
435      fileapi::GetFileSystemName(origin_url, file_system_type);
436  for (size_t i = 0; i < results->size(); ++i) {
437    DictionaryValue* entry = new DictionaryValue();
438    entry->SetString("fileSystemName", file_system_name);
439    entry->SetString("fileSystemRoot", file_system_root_url.spec());
440    entry->SetString("fileFullPath", "/" + results->at(i).path.value());
441    entry->SetBoolean("fileIsDirectory",
442                      results->at(i).entry.file_info().is_directory());
443    entries->Append(entry);
444  }
445
446  base::DictionaryValue* result = new DictionaryValue();
447  result->Set("entries", entries);
448  result->SetString("nextFeed", next_feed.spec());
449
450  SetResult(result);
451  SendResponse(true);
452}
453
454SearchDriveMetadataFunction::SearchDriveMetadataFunction() {
455}
456
457SearchDriveMetadataFunction::~SearchDriveMetadataFunction() {
458}
459
460bool SearchDriveMetadataFunction::RunImpl() {
461  DictionaryValue* search_params;
462  if (!args_->GetDictionary(0, &search_params))
463    return false;
464
465  std::string query;
466  if (!search_params->GetString("query", &query))
467    return false;
468
469  std::string types;
470  if (!search_params->GetString("types", &types))
471    return false;
472
473  int max_results = 0;
474  if (!search_params->GetInteger("maxResults", &max_results))
475    return false;
476
477  drive::util::Log(logging::LOG_INFO,
478                   "%s[%d] called. (types: '%s', maxResults: '%d')",
479                   name().c_str(),
480                   request_id(),
481                   types.c_str(),
482                   max_results);
483  set_log_on_completion(true);
484
485  drive::DriveIntegrationService* integration_service =
486      drive::DriveIntegrationServiceFactory::GetForProfile(profile_);
487  // |integration_service| is NULL if Drive is disabled.
488  if (!integration_service || !integration_service->file_system())
489    return false;
490
491  int options = drive::SEARCH_METADATA_ALL;
492  // TODO(hirono): Switch to the JSON scheme compiler. http://crbug.com/241693
493  if (types == "EXCLUDE_DIRECTORIES")
494    options = drive::SEARCH_METADATA_EXCLUDE_DIRECTORIES;
495  else if (types == "SHARED_WITH_ME")
496    options = drive::SEARCH_METADATA_SHARED_WITH_ME;
497  else if (types == "OFFLINE")
498    options = drive::SEARCH_METADATA_OFFLINE;
499  else
500    DCHECK_EQ("ALL", types);
501
502  integration_service->file_system()->SearchMetadata(
503      query,
504      options,
505      max_results,
506      base::Bind(&SearchDriveMetadataFunction::OnSearchMetadata, this));
507  return true;
508}
509
510void SearchDriveMetadataFunction::OnSearchMetadata(
511    drive::FileError error,
512    scoped_ptr<drive::MetadataSearchResultVector> results) {
513  if (error != drive::FILE_ERROR_OK) {
514    SendResponse(false);
515    return;
516  }
517
518  DCHECK(results.get());
519
520  base::ListValue* results_list = new ListValue();
521
522  // Convert Drive files to something File API stack can understand.  See
523  // file_browser_handler_custom_bindings.cc and
524  // file_browser_private_custom_bindings.js for how this is magically
525  // converted to a FileEntry.
526  GURL origin_url = source_url_.GetOrigin();
527  fileapi::FileSystemType file_system_type = fileapi::kFileSystemTypeExternal;
528  GURL file_system_root_url =
529      fileapi::GetFileSystemRootURI(origin_url, file_system_type);
530  std::string file_system_name =
531      fileapi::GetFileSystemName(origin_url, file_system_type);
532  for (size_t i = 0; i < results->size(); ++i) {
533    DictionaryValue* result_dict = new DictionaryValue();
534
535    // FileEntry fields.
536    DictionaryValue* entry = new DictionaryValue();
537    entry->SetString("fileSystemName", file_system_name);
538    entry->SetString("fileSystemRoot", file_system_root_url.spec());
539    entry->SetString("fileFullPath", "/" + results->at(i).path.value());
540    entry->SetBoolean("fileIsDirectory",
541                      results->at(i).entry.file_info().is_directory());
542
543    result_dict->Set("entry", entry);
544    result_dict->SetString("highlightedBaseName",
545                           results->at(i).highlighted_base_name);
546    results_list->Append(result_dict);
547  }
548
549  SetResult(results_list);
550  SendResponse(true);
551}
552
553ClearDriveCacheFunction::ClearDriveCacheFunction() {
554}
555
556ClearDriveCacheFunction::~ClearDriveCacheFunction() {
557}
558
559bool ClearDriveCacheFunction::RunImpl() {
560  drive::DriveIntegrationService* integration_service =
561      drive::DriveIntegrationServiceFactory::GetForProfile(profile_);
562  // |integration_service| is NULL if Drive is disabled.
563  if (!integration_service || !integration_service->file_system())
564    return false;
565
566  // TODO(yoshiki): Receive a callback from JS-side and pass it to
567  // ClearCacheAndRemountFileSystem(). http://crbug.com/140511
568  integration_service->ClearCacheAndRemountFileSystem(
569      base::Bind(&DoNothingWithBool));
570
571  SendResponse(true);
572  return true;
573}
574
575GetDriveConnectionStateFunction::GetDriveConnectionStateFunction() {
576}
577
578GetDriveConnectionStateFunction::~GetDriveConnectionStateFunction() {
579}
580
581bool GetDriveConnectionStateFunction::RunImpl() {
582  scoped_ptr<DictionaryValue> value(new DictionaryValue());
583  scoped_ptr<ListValue> reasons(new ListValue());
584
585  std::string type_string;
586  drive::DriveIntegrationService* integration_service =
587      drive::DriveIntegrationServiceFactory::GetForProfile(profile_);
588
589  bool ready = integration_service &&
590      integration_service->drive_service()->CanSendRequest();
591  bool is_connection_cellular =
592      net::NetworkChangeNotifier::IsConnectionCellular(
593          net::NetworkChangeNotifier::GetConnectionType());
594
595  if (net::NetworkChangeNotifier::IsOffline() || !ready) {
596    type_string = kDriveConnectionTypeOffline;
597    if (net::NetworkChangeNotifier::IsOffline())
598      reasons->AppendString(kDriveConnectionReasonNoNetwork);
599    if (!ready)
600      reasons->AppendString(kDriveConnectionReasonNotReady);
601    if (!integration_service)
602      reasons->AppendString(kDriveConnectionReasonNoService);
603  } else if (
604      is_connection_cellular &&
605      profile_->GetPrefs()->GetBoolean(prefs::kDisableDriveOverCellular)) {
606    type_string = kDriveConnectionTypeMetered;
607  } else {
608    type_string = kDriveConnectionTypeOnline;
609  }
610
611  value->SetString("type", type_string);
612  value->Set("reasons", reasons.release());
613  SetResult(value.release());
614
615  drive::util::Log(logging::LOG_INFO, "%s succeeded.", name().c_str());
616  return true;
617}
618
619RequestAccessTokenFunction::RequestAccessTokenFunction() {
620}
621
622RequestAccessTokenFunction::~RequestAccessTokenFunction() {
623}
624
625bool RequestAccessTokenFunction::RunImpl() {
626  drive::DriveIntegrationService* integration_service =
627      drive::DriveIntegrationServiceFactory::GetForProfile(profile_);
628  bool refresh;
629  args_->GetBoolean(0, &refresh);
630
631  if (!integration_service) {
632    SetResult(new base::StringValue(""));
633    SendResponse(true);
634    return true;
635  }
636
637  // If refreshing is requested, then clear the token to refetch it.
638  if (refresh)
639    integration_service->drive_service()->ClearAccessToken();
640
641  // Retrieve the cached auth token (if available), otherwise the AuthService
642  // instance will try to refetch it.
643  integration_service->drive_service()->RequestAccessToken(
644      base::Bind(&RequestAccessTokenFunction::OnAccessTokenFetched, this));
645  return true;
646}
647
648void RequestAccessTokenFunction::OnAccessTokenFetched(
649    google_apis::GDataErrorCode code, const std::string& access_token) {
650  SetResult(new base::StringValue(access_token));
651  SendResponse(true);
652}
653
654GetShareUrlFunction::GetShareUrlFunction() {
655}
656
657GetShareUrlFunction::~GetShareUrlFunction() {
658}
659
660bool GetShareUrlFunction::RunImpl() {
661  std::string file_url;
662  if (!args_->GetString(0, &file_url))
663    return false;
664
665  const base::FilePath path = util::GetLocalPathFromURL(
666      render_view_host(), profile(), GURL(file_url));
667  DCHECK(drive::util::IsUnderDriveMountPoint(path));
668
669  base::FilePath drive_path = drive::util::ExtractDrivePath(path);
670
671  drive::DriveIntegrationService* integration_service =
672      drive::DriveIntegrationServiceFactory::GetForProfile(profile_);
673  // |integration_service| is NULL if Drive is disabled.
674  if (!integration_service)
675    return false;
676
677  integration_service->file_system()->GetShareUrl(
678      drive_path,
679      util::GetFileManagerBaseUrl(),  // embed origin
680      base::Bind(&GetShareUrlFunction::OnGetShareUrl, this));
681  return true;
682}
683
684
685void GetShareUrlFunction::OnGetShareUrl(drive::FileError error,
686                                        const GURL& share_url) {
687  if (error != drive::FILE_ERROR_OK) {
688    error_ = "Share Url for this item is not available.";
689    SendResponse(false);
690    return;
691  }
692
693  SetResult(new base::StringValue(share_url.spec()));
694  SendResponse(true);
695}
696
697}  // namespace file_manager
698