private_api_drive.cc revision 3240926e260ce088908e02ac07a6cf7b0c0cbf44
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_manager_util.h"
13#include "chrome/browser/chromeos/extensions/file_manager/file_tasks.h"
14#include "chrome/browser/chromeos/extensions/file_manager/private_api_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
29// List of connection types of drive.
30// Keep this in sync with the DriveConnectionType in volume_manager.js.
31const char kDriveConnectionTypeOffline[] = "offline";
32const char kDriveConnectionTypeMetered[] = "metered";
33const char kDriveConnectionTypeOnline[] = "online";
34
35
36// List of reasons of kDriveConnectionType*.
37// Keep this in sync with the DriveConnectionReason in volume_manager.js.
38const char kDriveConnectionReasonNotReady[] = "not_ready";
39const char kDriveConnectionReasonNoNetwork[] = "no_network";
40const char kDriveConnectionReasonNoService[] = "no_service";
41
42// Does nothing with a bool parameter. Used as a placeholder for calling
43// ClearCacheAndRemountFileSystem(). TODO(yoshiki): Handle an error from
44// ClearCacheAndRemountFileSystem() properly: http://crbug.com/140511.
45void DoNothingWithBool(bool /* success */) {
46}
47
48// Copies properties from |entry_proto| to |property_dict|.
49void FillDriveEntryPropertiesValue(
50    const drive::ResourceEntry& entry_proto,
51    DictionaryValue* property_dict) {
52  property_dict->SetBoolean("sharedWithMe", entry_proto.shared_with_me());
53
54  if (!entry_proto.has_file_specific_info())
55    return;
56
57  const drive::FileSpecificInfo& file_specific_info =
58      entry_proto.file_specific_info();
59
60  property_dict->SetString("thumbnailUrl", file_specific_info.thumbnail_url());
61  property_dict->SetBoolean("isHosted",
62                            file_specific_info.is_hosted_document());
63  property_dict->SetString("contentMimeType",
64                           file_specific_info.content_mime_type());
65}
66
67}  // namespace
68
69GetDriveEntryPropertiesFunction::GetDriveEntryPropertiesFunction() {
70}
71
72GetDriveEntryPropertiesFunction::~GetDriveEntryPropertiesFunction() {
73}
74
75bool GetDriveEntryPropertiesFunction::RunImpl() {
76  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
77
78  std::string file_url_str;
79  if (args_->GetSize() != 1 || !args_->GetString(0, &file_url_str))
80    return false;
81
82  GURL file_url = GURL(file_url_str);
83  file_path_ = drive::util::ExtractDrivePath(
84      util::GetLocalPathFromURL(render_view_host(), profile(), file_url));
85
86  properties_.reset(new base::DictionaryValue);
87  properties_->SetString("fileUrl", file_url.spec());
88
89  // Start getting the file info.
90  drive::DriveIntegrationService* integration_service =
91      drive::DriveIntegrationServiceFactory::GetForProfile(profile_);
92  // |integration_service| is NULL if Drive is disabled.
93  if (!integration_service) {
94    CompleteGetFileProperties(drive::FILE_ERROR_FAILED);
95    return true;
96  }
97
98  integration_service->file_system()->GetResourceEntryByPath(
99      file_path_,
100      base::Bind(&GetDriveEntryPropertiesFunction::OnGetFileInfo, this));
101  return true;
102}
103
104void GetDriveEntryPropertiesFunction::OnGetFileInfo(
105    drive::FileError error,
106    scoped_ptr<drive::ResourceEntry> entry) {
107  DCHECK(properties_);
108
109  if (error != drive::FILE_ERROR_OK) {
110    CompleteGetFileProperties(error);
111    return;
112  }
113  DCHECK(entry);
114
115  FillDriveEntryPropertiesValue(*entry, properties_.get());
116
117  drive::DriveIntegrationService* integration_service =
118      drive::DriveIntegrationServiceFactory::GetForProfile(profile_);
119  // |integration_service| is NULL if Drive is disabled.
120  if (!integration_service) {
121    CompleteGetFileProperties(drive::FILE_ERROR_FAILED);
122    return;
123  }
124
125  // The properties meaningful for directories are already filled in
126  // FillDriveEntryPropertiesValue().
127  if (entry.get() && !entry->has_file_specific_info()) {
128    CompleteGetFileProperties(error);
129    return;
130  }
131
132  const drive::FileSpecificInfo& file_specific_info =
133      entry->file_specific_info();
134
135  // Get drive WebApps that can accept this file.
136  ScopedVector<drive::DriveAppInfo> drive_apps;
137  integration_service->drive_app_registry()->GetAppsForFile(
138      file_path_, file_specific_info.content_mime_type(), &drive_apps);
139  if (!drive_apps.empty()) {
140    std::string default_task_id = file_tasks::GetDefaultTaskIdFromPrefs(
141        profile_,
142        file_specific_info.content_mime_type(),
143        file_path_.Extension());
144    std::string default_app_id;
145    file_tasks::CrackTaskID(
146        default_task_id, &default_app_id, NULL, NULL);
147
148    ListValue* apps = new ListValue();
149    properties_->Set("driveApps", apps);
150    for (ScopedVector<drive::DriveAppInfo>::const_iterator it =
151             drive_apps.begin();
152         it != drive_apps.end(); ++it) {
153      const drive::DriveAppInfo* app_info = *it;
154      DictionaryValue* app = new DictionaryValue();
155      app->SetString("appId", app_info->app_id);
156      app->SetString("appName", app_info->app_name);
157      GURL app_icon = util::FindPreferredIcon(app_info->app_icons,
158                                              util::kPreferredIconSize);
159      if (!app_icon.is_empty())
160        app->SetString("appIcon", app_icon.spec());
161      GURL doc_icon = util::FindPreferredIcon(app_info->document_icons,
162                                              util::kPreferredIconSize);
163      if (!doc_icon.is_empty())
164        app->SetString("docIcon", doc_icon.spec());
165      app->SetString("objectType", app_info->object_type);
166      app->SetBoolean("isPrimary", default_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::GetFileBrowserExtensionUrl(),  // 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