developer_private_api.cc revision f2477e01787aa58f445919b809d89e252beef54f
1// Copyright (c) 2012 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/extensions/api/developer_private/developer_private_api.h"
6
7#include "apps/app_load_service.h"
8#include "apps/app_restore_service.h"
9#include "apps/saved_files_service.h"
10#include "apps/shell_window.h"
11#include "apps/shell_window_registry.h"
12#include "base/base64.h"
13#include "base/command_line.h"
14#include "base/file_util.h"
15#include "base/files/file_enumerator.h"
16#include "base/i18n/file_util_icu.h"
17#include "base/strings/string_number_conversions.h"
18#include "base/strings/utf_string_conversions.h"
19#include "base/values.h"
20#include "chrome/browser/chrome_notification_types.h"
21#include "chrome/browser/devtools/devtools_window.h"
22#include "chrome/browser/extensions/api/developer_private/developer_private_api_factory.h"
23#include "chrome/browser/extensions/api/developer_private/entry_picker.h"
24#include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
25#include "chrome/browser/extensions/devtools_util.h"
26#include "chrome/browser/extensions/extension_disabled_ui.h"
27#include "chrome/browser/extensions/extension_error_reporter.h"
28#include "chrome/browser/extensions/extension_service.h"
29#include "chrome/browser/extensions/extension_system.h"
30#include "chrome/browser/extensions/extension_util.h"
31#include "chrome/browser/extensions/unpacked_installer.h"
32#include "chrome/browser/extensions/updater/extension_updater.h"
33#include "chrome/browser/platform_util.h"
34#include "chrome/browser/profiles/profile.h"
35#include "chrome/browser/sync_file_system/drive_backend_v1/drive_file_sync_service.h"
36#include "chrome/browser/sync_file_system/syncable_file_system_util.h"
37#include "chrome/browser/ui/chrome_select_file_policy.h"
38#include "chrome/browser/ui/webui/extensions/extension_icon_source.h"
39#include "chrome/common/extensions/api/developer_private.h"
40#include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
41#include "chrome/common/extensions/manifest_handlers/icons_handler.h"
42#include "chrome/common/extensions/manifest_url_handler.h"
43#include "chrome/common/url_constants.h"
44#include "content/public/browser/browser_thread.h"
45#include "content/public/browser/notification_service.h"
46#include "content/public/browser/render_process_host.h"
47#include "content/public/browser/render_view_host.h"
48#include "content/public/browser/site_instance.h"
49#include "content/public/browser/storage_partition.h"
50#include "content/public/browser/web_contents.h"
51#include "extensions/browser/management_policy.h"
52#include "extensions/browser/view_type_utils.h"
53#include "extensions/common/constants.h"
54#include "extensions/common/extension_resource.h"
55#include "extensions/common/install_warning.h"
56#include "extensions/common/manifest_handlers/background_info.h"
57#include "extensions/common/manifest_handlers/incognito_info.h"
58#include "extensions/common/manifest_handlers/offline_enabled_info.h"
59#include "extensions/common/switches.h"
60#include "grit/chromium_strings.h"
61#include "grit/generated_resources.h"
62#include "grit/theme_resources.h"
63#include "net/base/net_util.h"
64#include "ui/base/l10n/l10n_util.h"
65#include "ui/base/resource/resource_bundle.h"
66#include "ui/base/webui/web_ui_util.h"
67#include "webkit/browser/fileapi/file_system_context.h"
68#include "webkit/browser/fileapi/file_system_operation.h"
69#include "webkit/browser/fileapi/file_system_operation_runner.h"
70#include "webkit/common/blob/shareable_file_reference.h"
71
72using apps::ShellWindow;
73using apps::ShellWindowRegistry;
74using content::RenderViewHost;
75
76namespace extensions {
77
78namespace developer_private = api::developer_private;
79
80namespace {
81
82const base::FilePath::CharType kUnpackedAppsFolder[]
83    = FILE_PATH_LITERAL("apps_target");
84
85ExtensionUpdater* GetExtensionUpdater(Profile* profile) {
86    return profile->GetExtensionService()->updater();
87}
88
89GURL GetImageURLFromData(std::string contents) {
90  std::string contents_base64;
91  if (!base::Base64Encode(contents, &contents_base64))
92    return GURL();
93
94  // TODO(dvh): make use of chrome::kDataScheme. Filed as crbug/297301.
95  const char kDataURLPrefix[] = "data:image;base64,";
96  return GURL(kDataURLPrefix + contents_base64);
97}
98
99GURL GetDefaultImageURL(developer_private::ItemType type) {
100  int icon_resource_id;
101  switch (type) {
102    case developer::ITEM_TYPE_LEGACY_PACKAGED_APP:
103    case developer::ITEM_TYPE_HOSTED_APP:
104    case developer::ITEM_TYPE_PACKAGED_APP:
105      icon_resource_id = IDR_APP_DEFAULT_ICON;
106      break;
107    default:
108      icon_resource_id = IDR_EXTENSION_DEFAULT_ICON;
109      break;
110  }
111
112  return GetImageURLFromData(
113      ResourceBundle::GetSharedInstance().GetRawDataResourceForScale(
114          icon_resource_id, ui::SCALE_FACTOR_100P).as_string());
115}
116
117// TODO(dvh): This code should be refactored and moved to
118// extensions::ImageLoader. Also a resize should be performed to avoid
119// potential huge URLs: crbug/297298.
120GURL ToDataURL(const base::FilePath& path, developer_private::ItemType type) {
121  std::string contents;
122  if (path.empty() || !base::ReadFileToString(path, &contents))
123    return GetDefaultImageURL(type);
124
125  return GetImageURLFromData(contents);
126}
127
128bool ValidateFolderName(const base::FilePath::StringType& name) {
129  base::FilePath::StringType name_sanitized(name);
130  file_util::ReplaceIllegalCharactersInPath(&name_sanitized, '_');
131  return name == name_sanitized;
132}
133
134const Extension* GetExtensionByPath(const ExtensionSet* extensions,
135                                    const base::FilePath& path) {
136  base::FilePath extension_path = base::MakeAbsoluteFilePath(path);
137  for (ExtensionSet::const_iterator iter = extensions->begin();
138       iter != extensions->end(); ++iter) {
139    if ((*iter)->path() == extension_path)
140      return iter->get();
141  }
142  return NULL;
143}
144
145std::string GetExtensionID(const RenderViewHost* render_view_host) {
146  if (!render_view_host->GetSiteInstance())
147    return std::string();
148
149  return render_view_host->GetSiteInstance()->GetSiteURL().host();
150}
151
152}  // namespace
153
154namespace AllowFileAccess = api::developer_private::AllowFileAccess;
155namespace AllowIncognito = api::developer_private::AllowIncognito;
156namespace ChoosePath = api::developer_private::ChoosePath;
157namespace Enable = api::developer_private::Enable;
158namespace GetItemsInfo = api::developer_private::GetItemsInfo;
159namespace Inspect = api::developer_private::Inspect;
160namespace PackDirectory = api::developer_private::PackDirectory;
161namespace Reload = api::developer_private::Reload;
162
163DeveloperPrivateAPI* DeveloperPrivateAPI::Get(Profile* profile) {
164  return DeveloperPrivateAPIFactory::GetForProfile(profile);
165}
166
167DeveloperPrivateAPI::DeveloperPrivateAPI(Profile* profile) : profile_(profile) {
168  RegisterNotifications();
169}
170
171DeveloperPrivateEventRouter::DeveloperPrivateEventRouter(Profile* profile)
172: profile_(profile) {
173  int types[] = {
174    chrome::NOTIFICATION_EXTENSION_INSTALLED,
175    chrome::NOTIFICATION_EXTENSION_UNINSTALLED,
176    chrome::NOTIFICATION_EXTENSION_LOADED,
177    chrome::NOTIFICATION_EXTENSION_UNLOADED,
178    chrome::NOTIFICATION_EXTENSION_VIEW_REGISTERED,
179    chrome::NOTIFICATION_EXTENSION_VIEW_UNREGISTERED
180  };
181
182  CHECK(registrar_.IsEmpty());
183  for (size_t i = 0; i < arraysize(types); ++i) {
184    registrar_.Add(this,
185                   types[i],
186                   content::Source<Profile>(profile_));
187  }
188}
189
190
191DeveloperPrivateEventRouter::~DeveloperPrivateEventRouter() {}
192
193void DeveloperPrivateEventRouter::Observe(
194    int type,
195    const content::NotificationSource& source,
196    const content::NotificationDetails& details) {
197  const char* event_name = NULL;
198  Profile* profile = content::Source<Profile>(source).ptr();
199  CHECK(profile);
200  CHECK(profile_->IsSameProfile(profile));
201  developer::EventData event_data;
202  const Extension* extension = NULL;
203
204  switch (type) {
205    case chrome::NOTIFICATION_EXTENSION_INSTALLED:
206      event_data.event_type = developer::EVENT_TYPE_INSTALLED;
207      extension =
208          content::Details<const InstalledExtensionInfo>(details)->extension;
209      break;
210    case chrome::NOTIFICATION_EXTENSION_UNINSTALLED:
211      event_data.event_type = developer::EVENT_TYPE_UNINSTALLED;
212      extension = content::Details<const Extension>(details).ptr();
213      break;
214    case chrome::NOTIFICATION_EXTENSION_LOADED:
215      event_data.event_type = developer::EVENT_TYPE_LOADED;
216      extension = content::Details<const Extension>(details).ptr();
217      break;
218    case chrome::NOTIFICATION_EXTENSION_UNLOADED:
219      event_data.event_type = developer::EVENT_TYPE_UNLOADED;
220      extension =
221          content::Details<const UnloadedExtensionInfo>(details)->extension;
222      break;
223    case chrome::NOTIFICATION_EXTENSION_VIEW_UNREGISTERED:
224      event_data.event_type = developer::EVENT_TYPE_VIEW_UNREGISTERED;
225      event_data.item_id = GetExtensionID(
226          content::Details<const RenderViewHost>(details).ptr());
227      break;
228    case chrome::NOTIFICATION_EXTENSION_VIEW_REGISTERED:
229      event_data.event_type = developer::EVENT_TYPE_VIEW_REGISTERED;
230      event_data.item_id = GetExtensionID(
231          content::Details<const RenderViewHost>(details).ptr());
232      break;
233    default:
234      NOTREACHED();
235      return;
236  }
237
238  if (extension)
239    event_data.item_id = extension->id();
240
241  scoped_ptr<ListValue> args(new ListValue());
242  args->Append(event_data.ToValue().release());
243
244  event_name = developer_private::OnItemStateChanged::kEventName;
245  scoped_ptr<Event> event(new Event(event_name, args.Pass()));
246  ExtensionSystem::Get(profile)->event_router()->BroadcastEvent(event.Pass());
247}
248
249void DeveloperPrivateAPI::SetLastUnpackedDirectory(const base::FilePath& path) {
250  last_unpacked_directory_ = path;
251}
252
253void DeveloperPrivateAPI::RegisterNotifications() {
254  ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
255      this, developer_private::OnItemStateChanged::kEventName);
256}
257
258DeveloperPrivateAPI::~DeveloperPrivateAPI() {}
259
260void DeveloperPrivateAPI::Shutdown() {}
261
262void DeveloperPrivateAPI::OnListenerAdded(
263    const EventListenerInfo& details) {
264  if (!developer_private_event_router_)
265    developer_private_event_router_.reset(
266        new DeveloperPrivateEventRouter(profile_));
267}
268
269void DeveloperPrivateAPI::OnListenerRemoved(
270    const EventListenerInfo& details) {
271  if (!ExtensionSystem::Get(profile_)->event_router()->HasEventListener(
272          developer_private::OnItemStateChanged::kEventName))
273    developer_private_event_router_.reset(NULL);
274}
275
276namespace api {
277
278bool DeveloperPrivateAutoUpdateFunction::RunImpl() {
279  ExtensionUpdater* updater = GetExtensionUpdater(GetProfile());
280  if (updater)
281    updater->CheckNow(ExtensionUpdater::CheckParams());
282  SetResult(new base::FundamentalValue(true));
283  return true;
284}
285
286DeveloperPrivateAutoUpdateFunction::~DeveloperPrivateAutoUpdateFunction() {}
287
288scoped_ptr<developer::ItemInfo>
289  DeveloperPrivateGetItemsInfoFunction::CreateItemInfo(
290      const Extension& item,
291      bool item_is_enabled) {
292  scoped_ptr<developer::ItemInfo> info(new developer::ItemInfo());
293
294  ExtensionSystem* system = ExtensionSystem::Get(GetProfile());
295  ExtensionService* service = GetProfile()->GetExtensionService();
296
297  info->id = item.id();
298  info->name = item.name();
299  info->enabled = service->IsExtensionEnabled(info->id);
300  info->offline_enabled = OfflineEnabledInfo::IsOfflineEnabled(&item);
301  info->version = item.VersionString();
302  info->description = item.description();
303
304  if (item.is_app()) {
305    if (item.is_legacy_packaged_app())
306      info->type = developer::ITEM_TYPE_LEGACY_PACKAGED_APP;
307    else if (item.is_hosted_app())
308      info->type = developer::ITEM_TYPE_HOSTED_APP;
309    else if (item.is_platform_app())
310      info->type = developer::ITEM_TYPE_PACKAGED_APP;
311    else
312      NOTREACHED();
313  } else if (item.is_theme()) {
314    info->type = developer::ITEM_TYPE_THEME;
315  } else if (item.is_extension()) {
316    info->type = developer::ITEM_TYPE_EXTENSION;
317  } else {
318    NOTREACHED();
319  }
320
321  if (Manifest::IsUnpackedLocation(item.location())) {
322    info->path.reset(
323        new std::string(UTF16ToUTF8(item.path().LossyDisplayName())));
324    for (std::vector<extensions::InstallWarning>::const_iterator it =
325             item.install_warnings().begin();
326         it != item.install_warnings().end(); ++it) {
327      developer::InstallWarning* warning = new developer::InstallWarning();
328      warning->message = it->message;
329      info->install_warnings.push_back(make_linked_ptr(warning));
330    }
331  }
332
333  info->incognito_enabled =
334      extension_util::IsIncognitoEnabled(item.id(),service);
335  info->wants_file_access = item.wants_file_access();
336  info->allow_file_access = extension_util::AllowFileAccess(&item, service);
337  info->allow_reload = Manifest::IsUnpackedLocation(item.location());
338  info->is_unpacked = Manifest::IsUnpackedLocation(item.location());
339  info->terminated = service->terminated_extensions()->Contains(item.id());
340  info->allow_incognito = item.can_be_incognito_enabled();
341
342  info->homepage_url.reset(new std::string(
343      ManifestURL::GetHomepageURL(&item).spec()));
344  if (!ManifestURL::GetOptionsPage(&item).is_empty()) {
345    info->options_url.reset(
346        new std::string(ManifestURL::GetOptionsPage(&item).spec()));
347  }
348
349  if (!ManifestURL::GetUpdateURL(&item).is_empty()) {
350    info->update_url.reset(
351        new std::string(ManifestURL::GetUpdateURL(&item).spec()));
352  }
353
354  if (item.is_app()) {
355    info->app_launch_url.reset(new std::string(
356        extensions::AppLaunchInfo::GetFullLaunchURL(&item).spec()));
357  }
358
359  info->may_disable = system->management_policy()->
360      UserMayModifySettings(&item, NULL);
361  info->is_app = item.is_app();
362  info->views = GetInspectablePagesForExtension(&item, item_is_enabled);
363
364  return info.Pass();
365}
366
367void DeveloperPrivateGetItemsInfoFunction::GetIconsOnFileThread(
368    ItemInfoList item_list,
369    const std::map<std::string, ExtensionResource> idToIcon) {
370  for (ItemInfoList::iterator iter = item_list.begin();
371       iter != item_list.end(); ++iter) {
372    developer_private::ItemInfo* info = iter->get();
373    std::map<std::string, ExtensionResource>::const_iterator resource_ptr
374        = idToIcon.find(info->id);
375    if (resource_ptr != idToIcon.end()) {
376      info->icon_url =
377          ToDataURL(resource_ptr->second.GetFilePath(), info->type).spec();
378    }
379  }
380
381  results_ = developer::GetItemsInfo::Results::Create(item_list);
382  content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
383      base::Bind(&DeveloperPrivateGetItemsInfoFunction::SendResponse,
384                 this,
385                 true));
386}
387
388void DeveloperPrivateGetItemsInfoFunction::
389    GetInspectablePagesForExtensionProcess(
390        const Extension* extension,
391        const std::set<content::RenderViewHost*>& views,
392        ItemInspectViewList* result) {
393  bool has_generated_background_page =
394      BackgroundInfo::HasGeneratedBackgroundPage(extension);
395  for (std::set<content::RenderViewHost*>::const_iterator iter = views.begin();
396       iter != views.end(); ++iter) {
397    content::RenderViewHost* host = *iter;
398    content::WebContents* web_contents =
399        content::WebContents::FromRenderViewHost(host);
400    ViewType host_type = GetViewType(web_contents);
401    if (VIEW_TYPE_EXTENSION_POPUP == host_type ||
402        VIEW_TYPE_EXTENSION_DIALOG == host_type)
403      continue;
404
405    content::RenderProcessHost* process = host->GetProcess();
406    bool is_background_page =
407        (web_contents->GetURL() == BackgroundInfo::GetBackgroundURL(extension));
408    result->push_back(constructInspectView(
409        web_contents->GetURL(),
410        process->GetID(),
411        host->GetRoutingID(),
412        process->GetBrowserContext()->IsOffTheRecord(),
413        is_background_page && has_generated_background_page));
414  }
415}
416
417void DeveloperPrivateGetItemsInfoFunction::
418    GetShellWindowPagesForExtensionProfile(
419        const Extension* extension,
420        ItemInspectViewList* result) {
421  ShellWindowRegistry* registry = ShellWindowRegistry::Get(GetProfile());
422  if (!registry) return;
423
424  const ShellWindowRegistry::ShellWindowList windows =
425      registry->GetShellWindowsForApp(extension->id());
426
427  bool has_generated_background_page =
428      BackgroundInfo::HasGeneratedBackgroundPage(extension);
429  for (ShellWindowRegistry::const_iterator it = windows.begin();
430       it != windows.end(); ++it) {
431    content::WebContents* web_contents = (*it)->web_contents();
432    RenderViewHost* host = web_contents->GetRenderViewHost();
433    content::RenderProcessHost* process = host->GetProcess();
434    bool is_background_page =
435        (web_contents->GetURL() == BackgroundInfo::GetBackgroundURL(extension));
436    result->push_back(constructInspectView(
437        web_contents->GetURL(),
438        process->GetID(),
439        host->GetRoutingID(),
440        process->GetBrowserContext()->IsOffTheRecord(),
441        is_background_page && has_generated_background_page));
442  }
443}
444
445linked_ptr<developer::ItemInspectView> DeveloperPrivateGetItemsInfoFunction::
446    constructInspectView(
447        const GURL& url,
448        int render_process_id,
449        int render_view_id,
450        bool incognito,
451        bool generated_background_page) {
452  linked_ptr<developer::ItemInspectView> view(new developer::ItemInspectView());
453
454  if (url.scheme() == kExtensionScheme) {
455    // No leading slash.
456    view->path = url.path().substr(1);
457  } else {
458    // For live pages, use the full URL.
459    view->path = url.spec();
460  }
461
462  view->render_process_id = render_process_id;
463  view->render_view_id = render_view_id;
464  view->incognito = incognito;
465  view->generated_background_page = generated_background_page;
466  return view;
467}
468
469ItemInspectViewList DeveloperPrivateGetItemsInfoFunction::
470    GetInspectablePagesForExtension(
471        const Extension* extension,
472        bool extension_is_enabled) {
473
474  ItemInspectViewList result;
475  // Get the extension process's active views.
476  extensions::ProcessManager* process_manager =
477      ExtensionSystem::Get(GetProfile())->process_manager();
478  GetInspectablePagesForExtensionProcess(
479      extension,
480      process_manager->GetRenderViewHostsForExtension(extension->id()),
481      &result);
482
483  // Get shell window views
484  GetShellWindowPagesForExtensionProfile(extension, &result);
485
486  // Include a link to start the lazy background page, if applicable.
487  if (BackgroundInfo::HasLazyBackgroundPage(extension) &&
488      extension_is_enabled &&
489      !process_manager->GetBackgroundHostForExtension(extension->id())) {
490    result.push_back(constructInspectView(
491        BackgroundInfo::GetBackgroundURL(extension),
492        -1,
493        -1,
494        false,
495        BackgroundInfo::HasGeneratedBackgroundPage(extension)));
496  }
497
498  ExtensionService* service = GetProfile()->GetExtensionService();
499  // Repeat for the incognito process, if applicable. Don't try to get
500  // shell windows for incognito process.
501  if (service->profile()->HasOffTheRecordProfile() &&
502      IncognitoInfo::IsSplitMode(extension)) {
503    process_manager = ExtensionSystem::Get(
504        service->profile()->GetOffTheRecordProfile())->process_manager();
505    GetInspectablePagesForExtensionProcess(
506        extension,
507        process_manager->GetRenderViewHostsForExtension(extension->id()),
508        &result);
509
510    if (BackgroundInfo::HasLazyBackgroundPage(extension) &&
511        extension_is_enabled &&
512        !process_manager->GetBackgroundHostForExtension(extension->id())) {
513    result.push_back(constructInspectView(
514        BackgroundInfo::GetBackgroundURL(extension),
515        -1,
516        -1,
517        false,
518        BackgroundInfo::HasGeneratedBackgroundPage(extension)));
519    }
520  }
521
522  return result;
523}
524
525bool DeveloperPrivateGetItemsInfoFunction::RunImpl() {
526  scoped_ptr<developer::GetItemsInfo::Params> params(
527      developer::GetItemsInfo::Params::Create(*args_));
528  EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
529
530  bool include_disabled = params->include_disabled;
531  bool include_terminated = params->include_terminated;
532
533  ExtensionSet items;
534
535  ExtensionService* service = GetProfile()->GetExtensionService();
536
537  items.InsertAll(*service->extensions());
538
539  if (include_disabled) {
540    items.InsertAll(*service->disabled_extensions());
541  }
542
543  if (include_terminated) {
544    items.InsertAll(*service->terminated_extensions());
545  }
546
547  std::map<std::string, ExtensionResource> id_to_icon;
548  ItemInfoList item_list;
549
550  for (ExtensionSet::const_iterator iter = items.begin();
551       iter != items.end(); ++iter) {
552    const Extension& item = *iter->get();
553
554    ExtensionResource item_resource =
555        IconsInfo::GetIconResource(&item,
556                                   extension_misc::EXTENSION_ICON_MEDIUM,
557                                   ExtensionIconSet::MATCH_BIGGER);
558    id_to_icon[item.id()] = item_resource;
559
560    // Don't show component extensions and invisible apps.
561    if (item.ShouldNotBeVisible())
562      continue;
563
564    item_list.push_back(make_linked_ptr<developer::ItemInfo>(
565        CreateItemInfo(
566            item, service->IsExtensionEnabled(item.id())).release()));
567  }
568
569  content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE,
570      base::Bind(&DeveloperPrivateGetItemsInfoFunction::GetIconsOnFileThread,
571                 this,
572                 item_list,
573                 id_to_icon));
574
575  return true;
576}
577
578DeveloperPrivateGetItemsInfoFunction::~DeveloperPrivateGetItemsInfoFunction() {}
579
580bool DeveloperPrivateAllowFileAccessFunction::RunImpl() {
581  scoped_ptr<AllowFileAccess::Params> params(
582      AllowFileAccess::Params::Create(*args_));
583  EXTENSION_FUNCTION_VALIDATE(params.get());
584
585  EXTENSION_FUNCTION_VALIDATE(user_gesture_);
586
587  ExtensionSystem* system = ExtensionSystem::Get(GetProfile());
588  ManagementPolicy* management_policy = system->management_policy();
589  ExtensionService* service = GetProfile()->GetExtensionService();
590  const Extension* extension = service->GetInstalledExtension(params->item_id);
591  bool result = true;
592
593  if (!extension) {
594    result = false;
595  } else if (!management_policy->UserMayModifySettings(extension, NULL)) {
596    LOG(ERROR) << "Attempt to change allow file access of an extension that "
597               << "non-usermanagable was made. Extension id : "
598               << extension->id();
599    result = false;
600  } else {
601    extension_util::SetAllowFileAccess(extension, service, params->allow);
602    result = true;
603  }
604
605  return result;
606}
607
608DeveloperPrivateAllowFileAccessFunction::
609    ~DeveloperPrivateAllowFileAccessFunction() {}
610
611bool DeveloperPrivateAllowIncognitoFunction::RunImpl() {
612  scoped_ptr<AllowIncognito::Params> params(
613      AllowIncognito::Params::Create(*args_));
614  EXTENSION_FUNCTION_VALIDATE(params.get());
615
616  ExtensionService* service = GetProfile()->GetExtensionService();
617  const Extension* extension = service->GetInstalledExtension(params->item_id);
618  bool result = true;
619
620  if (!extension)
621    result = false;
622  else
623    extension_util::SetIsIncognitoEnabled(
624        extension->id(),service, params->allow);
625
626  return result;
627}
628
629DeveloperPrivateAllowIncognitoFunction::
630    ~DeveloperPrivateAllowIncognitoFunction() {}
631
632
633bool DeveloperPrivateReloadFunction::RunImpl() {
634  scoped_ptr<Reload::Params> params(Reload::Params::Create(*args_));
635  EXTENSION_FUNCTION_VALIDATE(params.get());
636
637  ExtensionService* service = GetProfile()->GetExtensionService();
638  CHECK(!params->item_id.empty());
639  service->ReloadExtension(params->item_id);
640  return true;
641}
642
643bool DeveloperPrivateShowPermissionsDialogFunction::RunImpl() {
644  EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &extension_id_));
645  ExtensionService* service = GetProfile()->GetExtensionService();
646  CHECK(!extension_id_.empty());
647  ShellWindowRegistry* registry = ShellWindowRegistry::Get(GetProfile());
648  DCHECK(registry);
649  ShellWindow* shell_window = registry->GetShellWindowForRenderViewHost(
650      render_view_host());
651  prompt_.reset(new ExtensionInstallPrompt(shell_window->web_contents()));
652  const Extension* extension = service->GetInstalledExtension(extension_id_);
653
654  if (!extension)
655    return false;
656
657  // Released by InstallUIAbort or InstallUIProceed.
658  AddRef();
659  std::vector<base::FilePath> retained_file_paths;
660  if (extension->HasAPIPermission(extensions::APIPermission::kFileSystem)) {
661    std::vector<apps::SavedFileEntry> retained_file_entries =
662        apps::SavedFilesService::Get(GetProfile())
663            ->GetAllFileEntries(extension_id_);
664    for (size_t i = 0; i < retained_file_entries.size(); i++) {
665      retained_file_paths.push_back(retained_file_entries[i].path);
666    }
667  }
668  prompt_->ReviewPermissions(this, extension, retained_file_paths);
669  return true;
670}
671
672DeveloperPrivateReloadFunction::~DeveloperPrivateReloadFunction() {}
673
674// This is called when the user clicks "Revoke File Access."
675void DeveloperPrivateShowPermissionsDialogFunction::InstallUIProceed() {
676  apps::SavedFilesService::Get(GetProfile())
677      ->ClearQueue(GetProfile()->GetExtensionService()->GetExtensionById(
678            extension_id_, true));
679  if (apps::AppRestoreService::Get(GetProfile())
680          ->IsAppRestorable(extension_id_))
681    apps::AppLoadService::Get(GetProfile())->RestartApplication(extension_id_);
682  SendResponse(true);
683  Release();
684}
685
686void DeveloperPrivateShowPermissionsDialogFunction::InstallUIAbort(
687    bool user_initiated) {
688  SendResponse(true);
689  Release();
690}
691
692DeveloperPrivateShowPermissionsDialogFunction::
693    DeveloperPrivateShowPermissionsDialogFunction() {}
694
695DeveloperPrivateShowPermissionsDialogFunction::
696    ~DeveloperPrivateShowPermissionsDialogFunction() {}
697
698DeveloperPrivateEnableFunction::DeveloperPrivateEnableFunction() {}
699
700bool DeveloperPrivateEnableFunction::RunImpl() {
701  scoped_ptr<Enable::Params> params(Enable::Params::Create(*args_));
702  EXTENSION_FUNCTION_VALIDATE(params.get());
703
704  std::string extension_id = params->item_id;
705
706  ExtensionSystem* system = ExtensionSystem::Get(GetProfile());
707  ManagementPolicy* policy = system->management_policy();
708  ExtensionService* service = GetProfile()->GetExtensionService();
709
710  const Extension* extension = service->GetInstalledExtension(extension_id);
711  if (!extension) {
712    LOG(ERROR) << "Did not find extension with id " << extension_id;
713    return false;
714  }
715  bool enable = params->enable;
716  if (!policy->UserMayModifySettings(extension, NULL) ||
717      (!enable && policy->MustRemainEnabled(extension, NULL)) ||
718      (enable && policy->MustRemainDisabled(extension, NULL, NULL))) {
719    LOG(ERROR) << "Attempt to change enable state denied by management policy. "
720               << "Extension id: " << extension_id.c_str();
721    return false;
722  }
723
724  if (enable) {
725    ExtensionPrefs* prefs = service->extension_prefs();
726    if (prefs->DidExtensionEscalatePermissions(extension_id)) {
727      ShellWindowRegistry* registry = ShellWindowRegistry::Get(GetProfile());
728      CHECK(registry);
729      ShellWindow* shell_window = registry->GetShellWindowForRenderViewHost(
730          render_view_host());
731      if (!shell_window) {
732        return false;
733      }
734
735      ShowExtensionDisabledDialog(
736          service, shell_window->web_contents(), extension);
737    } else if ((prefs->GetDisableReasons(extension_id) &
738                  Extension::DISABLE_UNSUPPORTED_REQUIREMENT) &&
739               !requirements_checker_.get()) {
740      // Recheck the requirements.
741      scoped_refptr<const Extension> extension =
742          service->GetExtensionById(extension_id,
743                                     true );// include_disabled
744      requirements_checker_.reset(new RequirementsChecker);
745      // Released by OnRequirementsChecked.
746      AddRef();
747      requirements_checker_->Check(
748          extension,
749          base::Bind(&DeveloperPrivateEnableFunction::OnRequirementsChecked,
750                     this, extension_id));
751    } else {
752      service->EnableExtension(extension_id);
753
754      // Make sure any browser action contained within it is not hidden.
755      ExtensionActionAPI::SetBrowserActionVisibility(
756          prefs, extension->id(), true);
757    }
758  } else {
759    service->DisableExtension(extension_id, Extension::DISABLE_USER_ACTION);
760  }
761  return true;
762}
763
764void DeveloperPrivateEnableFunction::OnRequirementsChecked(
765    std::string extension_id,
766    std::vector<std::string> requirements_errors) {
767  if (requirements_errors.empty()) {
768    ExtensionService* service = GetProfile()->GetExtensionService();
769    service->EnableExtension(extension_id);
770  } else {
771    ExtensionErrorReporter::GetInstance()->ReportError(
772        UTF8ToUTF16(JoinString(requirements_errors, ' ')),
773        true /* be noisy */);
774  }
775  Release();
776}
777
778DeveloperPrivateEnableFunction::~DeveloperPrivateEnableFunction() {}
779
780bool DeveloperPrivateInspectFunction::RunImpl() {
781  scoped_ptr<developer::Inspect::Params> params(
782      developer::Inspect::Params::Create(*args_));
783  EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
784  const developer::InspectOptions& options = params->options;
785
786  int render_process_id;
787  base::StringToInt(options.render_process_id, &render_process_id);
788
789  if (render_process_id == -1) {
790    // This is a lazy background page. Identify if it is a normal
791    // or incognito background page.
792    ExtensionService* service = GetProfile()->GetExtensionService();
793    if (options.incognito)
794      service = ExtensionSystem::Get(
795          service->profile()->GetOffTheRecordProfile())->extension_service();
796    const Extension* extension = service->extensions()->GetByID(
797        options.extension_id);
798    DCHECK(extension);
799    // Wakes up the background page and  opens the inspect window.
800    devtools_util::InspectBackgroundPage(extension, GetProfile());
801    return false;
802  }
803
804  int render_view_id;
805  base::StringToInt(options.render_view_id, &render_view_id);
806  content::RenderViewHost* host = content::RenderViewHost::FromID(
807      render_process_id, render_view_id);
808
809  if (!host) {
810    // This can happen if the host has gone away since the page was displayed.
811    return false;
812  }
813
814  DevToolsWindow::OpenDevToolsWindow(host);
815  return true;
816}
817
818DeveloperPrivateInspectFunction::~DeveloperPrivateInspectFunction() {}
819
820bool DeveloperPrivateLoadUnpackedFunction::RunImpl() {
821  string16 select_title =
822      l10n_util::GetStringUTF16(IDS_EXTENSION_LOAD_FROM_DIRECTORY);
823
824  // Balanced in FileSelected / FileSelectionCanceled.
825  AddRef();
826  bool result = ShowPicker(
827      ui::SelectFileDialog::SELECT_FOLDER,
828      DeveloperPrivateAPI::Get(GetProfile())->GetLastUnpackedDirectory(),
829      select_title,
830      ui::SelectFileDialog::FileTypeInfo(),
831      0);
832  return result;
833}
834
835void DeveloperPrivateLoadUnpackedFunction::FileSelected(
836    const base::FilePath& path) {
837  ExtensionService* service = GetProfile()->GetExtensionService();
838  UnpackedInstaller::Create(service)->Load(path);
839  DeveloperPrivateAPI::Get(GetProfile())->SetLastUnpackedDirectory(path);
840  SendResponse(true);
841  Release();
842}
843
844void DeveloperPrivateLoadUnpackedFunction::FileSelectionCanceled() {
845  SendResponse(false);
846  Release();
847}
848
849bool DeveloperPrivateChooseEntryFunction::ShowPicker(
850    ui::SelectFileDialog::Type picker_type,
851    const base::FilePath& last_directory,
852    const string16& select_title,
853    const ui::SelectFileDialog::FileTypeInfo& info,
854    int file_type_index) {
855  ShellWindowRegistry* registry = ShellWindowRegistry::Get(GetProfile());
856  DCHECK(registry);
857  ShellWindow* shell_window = registry->GetShellWindowForRenderViewHost(
858      render_view_host());
859  if (!shell_window) {
860    return false;
861  }
862
863  // The entry picker will hold a reference to this function instance,
864  // and subsequent sending of the function response) until the user has
865  // selected a file or cancelled the picker. At that point, the picker will
866  // delete itself.
867  new EntryPicker(this, shell_window->web_contents(), picker_type,
868  last_directory, select_title, info, file_type_index);
869  return true;
870}
871
872bool DeveloperPrivateChooseEntryFunction::RunImpl() { return false; }
873
874DeveloperPrivateChooseEntryFunction::~DeveloperPrivateChooseEntryFunction() {}
875
876void DeveloperPrivatePackDirectoryFunction::OnPackSuccess(
877    const base::FilePath& crx_file,
878    const base::FilePath& pem_file) {
879  developer::PackDirectoryResponse response;
880  response.message =
881      UTF16ToUTF8(PackExtensionJob::StandardSuccessMessage(crx_file, pem_file));
882  response.status = developer::PACK_STATUS_SUCCESS;
883  results_ = developer::PackDirectory::Results::Create(response);
884  SendResponse(true);
885  Release();
886}
887
888void DeveloperPrivatePackDirectoryFunction::OnPackFailure(
889    const std::string& error,
890    ExtensionCreator::ErrorType error_type) {
891  developer::PackDirectoryResponse response;
892  response.message = error;
893  if (error_type == ExtensionCreator::kCRXExists) {
894    response.item_path = item_path_str_;
895    response.pem_path = key_path_str_;
896    response.override_flags = ExtensionCreator::kOverwriteCRX;
897    response.status = developer::PACK_STATUS_WARNING;
898  } else {
899    response.status = developer::PACK_STATUS_ERROR;
900  }
901  results_ = developer::PackDirectory::Results::Create(response);
902  SendResponse(true);
903  Release();
904}
905
906bool DeveloperPrivatePackDirectoryFunction::RunImpl() {
907  scoped_ptr<PackDirectory::Params> params(
908      PackDirectory::Params::Create(*args_));
909  EXTENSION_FUNCTION_VALIDATE(params.get());
910
911  int flags = params->flags;
912  item_path_str_ = params->path;
913  key_path_str_ = params->private_key_path;
914
915  base::FilePath root_directory =
916      base::FilePath::FromUTF8Unsafe(item_path_str_);
917
918  base::FilePath key_file = base::FilePath::FromUTF8Unsafe(key_path_str_);
919
920  developer::PackDirectoryResponse response;
921  if (root_directory.empty()) {
922    if (item_path_str_.empty())
923      response.message = l10n_util::GetStringUTF8(
924          IDS_EXTENSION_PACK_DIALOG_ERROR_ROOT_REQUIRED);
925    else
926      response.message = l10n_util::GetStringUTF8(
927          IDS_EXTENSION_PACK_DIALOG_ERROR_ROOT_INVALID);
928
929    response.status = developer::PACK_STATUS_ERROR;
930    results_ = developer::PackDirectory::Results::Create(response);
931    SendResponse(true);
932    return true;
933  }
934
935  if (!key_path_str_.empty() && key_file.empty()) {
936    response.message = l10n_util::GetStringUTF8(
937        IDS_EXTENSION_PACK_DIALOG_ERROR_KEY_INVALID);
938    response.status = developer::PACK_STATUS_ERROR;
939    results_ = developer::PackDirectory::Results::Create(response);
940    SendResponse(true);
941    return true;
942  }
943
944  // Balanced in OnPackSuccess / OnPackFailure.
945  AddRef();
946
947  pack_job_ = new PackExtensionJob(this, root_directory, key_file, flags);
948  pack_job_->Start();
949  return true;
950}
951
952DeveloperPrivatePackDirectoryFunction::DeveloperPrivatePackDirectoryFunction()
953{}
954
955DeveloperPrivatePackDirectoryFunction::~DeveloperPrivatePackDirectoryFunction()
956{}
957
958DeveloperPrivateLoadUnpackedFunction::~DeveloperPrivateLoadUnpackedFunction() {}
959
960bool DeveloperPrivateExportSyncfsFolderToLocalfsFunction::RunImpl() {
961  // TODO(grv) : add unittests.
962  base::FilePath::StringType project_name;
963  EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &project_name));
964  if (!ValidateFolderName(project_name)) {
965    DVLOG(0) << "Invalid project_name : [" << project_name << "]";
966    return false;
967  }
968
969  context_ = content::BrowserContext::GetStoragePartition(
970      GetProfile(), render_view_host()->GetSiteInstance())
971                 ->GetFileSystemContext();
972
973  base::FilePath project_path(GetProfile()->GetPath());
974  project_path = project_path.Append(kUnpackedAppsFolder);
975  project_path = project_path.Append(project_name);
976
977  content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE,
978      base::Bind(&DeveloperPrivateExportSyncfsFolderToLocalfsFunction::
979                     ClearPrexistingDirectoryContent,
980                 this,
981                 project_path));
982
983  return true;
984}
985
986void DeveloperPrivateExportSyncfsFolderToLocalfsFunction::
987    ClearPrexistingDirectoryContent(const base::FilePath& project_path) {
988
989  // Clear the project directory before copying new files.
990  base::DeleteFile(project_path, true/*recursive*/);
991
992  pendingCopyOperationsCount_ = 1;
993
994  content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE,
995      base::Bind(&DeveloperPrivateExportSyncfsFolderToLocalfsFunction::
996                 ReadSyncFileSystemDirectory,
997                 this, project_path, project_path.BaseName()));
998}
999
1000void DeveloperPrivateExportSyncfsFolderToLocalfsFunction::
1001    ReadSyncFileSystemDirectory(const base::FilePath& project_path,
1002                                const base::FilePath& destination_path) {
1003  std::string origin_url(
1004      Extension::GetBaseURLFromExtensionId(extension_id()).spec());
1005  fileapi::FileSystemURL url(sync_file_system::CreateSyncableFileSystemURL(
1006      GURL(origin_url),
1007      destination_path));
1008
1009  context_->operation_runner()->ReadDirectory(
1010      url, base::Bind(&DeveloperPrivateExportSyncfsFolderToLocalfsFunction::
1011                      ReadSyncFileSystemDirectoryCb,
1012                      this, project_path, destination_path));
1013}
1014
1015void DeveloperPrivateExportSyncfsFolderToLocalfsFunction::
1016    ReadSyncFileSystemDirectoryCb(
1017    const base::FilePath& project_path,
1018    const base::FilePath& destination_path,
1019    base::PlatformFileError status,
1020    const fileapi::FileSystemOperation::FileEntryList& file_list,
1021    bool has_more) {
1022
1023  if (status != base::PLATFORM_FILE_OK) {
1024    DLOG(ERROR) << "Error in copying files from sync filesystem.";
1025    return;
1026  }
1027
1028  // We add 1 to the pending copy operations for both files and directories. We
1029  // release the directory copy operation once all the files under the directory
1030  // are added for copying. We do that to ensure that pendingCopyOperationsCount
1031  // does not become zero before all copy operations are finished.
1032  // In case the directory happens to be executing the last copy operation it
1033  // will call SendResponse to send the response to the API. The pending copy
1034  // operations of files are released by the CopyFile function.
1035  pendingCopyOperationsCount_ += file_list.size();
1036
1037  for (size_t i = 0; i < file_list.size(); ++i) {
1038    if (file_list[i].is_directory) {
1039      ReadSyncFileSystemDirectory(project_path.Append(file_list[i].name),
1040                                  destination_path.Append(file_list[i].name));
1041      continue;
1042    }
1043
1044    std::string origin_url(
1045        Extension::GetBaseURLFromExtensionId(extension_id()).spec());
1046    fileapi::FileSystemURL url(sync_file_system::CreateSyncableFileSystemURL(
1047        GURL(origin_url),
1048        destination_path.Append(file_list[i].name)));
1049    base::FilePath target_path = project_path;
1050    target_path = target_path.Append(file_list[i].name);
1051
1052    context_->operation_runner()->CreateSnapshotFile(
1053        url,
1054        base::Bind(
1055            &DeveloperPrivateExportSyncfsFolderToLocalfsFunction::
1056                SnapshotFileCallback,
1057            this,
1058            target_path));
1059
1060  }
1061
1062  // Directory copy operation released here.
1063  pendingCopyOperationsCount_--;
1064
1065  if (!pendingCopyOperationsCount_) {
1066    content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
1067        base::Bind(&DeveloperPrivateExportSyncfsFolderToLocalfsFunction::
1068                       SendResponse,
1069                   this,
1070                   success_));
1071  }
1072}
1073
1074void DeveloperPrivateExportSyncfsFolderToLocalfsFunction::SnapshotFileCallback(
1075    const base::FilePath& target_path,
1076    base::PlatformFileError result,
1077    const base::PlatformFileInfo& file_info,
1078    const base::FilePath& src_path,
1079    const scoped_refptr<webkit_blob::ShareableFileReference>& file_ref) {
1080  if (result != base::PLATFORM_FILE_OK) {
1081    SetError("Error in copying files from sync filesystem.");
1082    success_ = false;
1083    return;
1084  }
1085
1086  content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE,
1087      base::Bind(&DeveloperPrivateExportSyncfsFolderToLocalfsFunction::CopyFile,
1088                 this,
1089                 src_path,
1090                 target_path));
1091}
1092
1093void DeveloperPrivateExportSyncfsFolderToLocalfsFunction::CopyFile(
1094    const base::FilePath& src_path,
1095    const base::FilePath& target_path) {
1096  if (!file_util::CreateDirectory(target_path.DirName())) {
1097    SetError("Error in copying files from sync filesystem.");
1098    success_ = false;
1099  }
1100
1101  if (success_)
1102    base::CopyFile(src_path, target_path);
1103
1104  CHECK(pendingCopyOperationsCount_ > 0);
1105  pendingCopyOperationsCount_--;
1106
1107  if (!pendingCopyOperationsCount_) {
1108    content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
1109        base::Bind(&DeveloperPrivateExportSyncfsFolderToLocalfsFunction::
1110                       SendResponse,
1111                   this,
1112                   success_));
1113  }
1114}
1115
1116DeveloperPrivateExportSyncfsFolderToLocalfsFunction::
1117    DeveloperPrivateExportSyncfsFolderToLocalfsFunction()
1118    : pendingCopyOperationsCount_(0), success_(true) {}
1119
1120DeveloperPrivateExportSyncfsFolderToLocalfsFunction::
1121    ~DeveloperPrivateExportSyncfsFolderToLocalfsFunction() {}
1122
1123bool DeveloperPrivateLoadProjectFunction::RunImpl() {
1124  // TODO(grv) : add unit tests.
1125  base::FilePath::StringType project_name;
1126  EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &project_name));
1127  if (!ValidateFolderName(project_name)) {
1128    DVLOG(0) << "Invalid project_name : [" << project_name << "]";
1129    return false;
1130  }
1131
1132  base::FilePath path(GetProfile()->GetPath());
1133  path = path.Append(kUnpackedAppsFolder);
1134  // TODO(grv) : Sanitize / check project_name.
1135  path = path.Append(project_name);
1136  ExtensionService* service = GetProfile()->GetExtensionService();
1137  UnpackedInstaller::Create(service)->Load(path);
1138
1139  const ExtensionSet* extensions = service->extensions();
1140  // Released by GetUnpackedExtension.
1141  AddRef();
1142  content::BrowserThread::PostTask(content::BrowserThread::FILE, FROM_HERE,
1143      base::Bind(&DeveloperPrivateLoadProjectFunction::GetUnpackedExtension,
1144                 this, path, extensions));
1145  return true;
1146}
1147
1148void DeveloperPrivateLoadProjectFunction::GetUnpackedExtension(
1149    const base::FilePath& path,
1150    const ExtensionSet* extensions) {
1151  const Extension* extension = GetExtensionByPath(extensions, path);
1152  bool success = true;
1153  if (extension) {
1154    SetResult(new base::StringValue(extension->id()));
1155  } else {
1156    SetError("unable to load the project");
1157    success = false;
1158  }
1159  content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
1160      base::Bind(&DeveloperPrivateLoadProjectFunction::SendResponse,
1161                 this,
1162                 success));
1163  Release();
1164}
1165
1166DeveloperPrivateLoadProjectFunction::DeveloperPrivateLoadProjectFunction() {}
1167
1168DeveloperPrivateLoadProjectFunction::~DeveloperPrivateLoadProjectFunction() {}
1169
1170bool DeveloperPrivateChoosePathFunction::RunImpl() {
1171
1172  scoped_ptr<developer::ChoosePath::Params> params(
1173      developer::ChoosePath::Params::Create(*args_));
1174  EXTENSION_FUNCTION_VALIDATE(params.get() != NULL);
1175
1176  ui::SelectFileDialog::Type type = ui::SelectFileDialog::SELECT_FOLDER;
1177  ui::SelectFileDialog::FileTypeInfo info;
1178  if (params->select_type == developer::SELECT_TYPE_FILE) {
1179    type = ui::SelectFileDialog::SELECT_OPEN_FILE;
1180  }
1181  string16 select_title;
1182
1183  int file_type_index = 0;
1184  if (params->file_type == developer::FILE_TYPE_LOAD)
1185    select_title = l10n_util::GetStringUTF16(IDS_EXTENSION_LOAD_FROM_DIRECTORY);
1186  else if (params->file_type== developer::FILE_TYPE_PEM) {
1187    select_title = l10n_util::GetStringUTF16(
1188        IDS_EXTENSION_PACK_DIALOG_SELECT_KEY);
1189    info.extensions.push_back(std::vector<base::FilePath::StringType>());
1190    info.extensions.front().push_back(FILE_PATH_LITERAL("pem"));
1191    info.extension_description_overrides.push_back(
1192        l10n_util::GetStringUTF16(
1193            IDS_EXTENSION_PACK_DIALOG_KEY_FILE_TYPE_DESCRIPTION));
1194    info.include_all_files = true;
1195    file_type_index = 1;
1196  } else {
1197    NOTREACHED();
1198  }
1199
1200  // Balanced by FileSelected / FileSelectionCanceled.
1201  AddRef();
1202  bool result = ShowPicker(
1203      type,
1204      DeveloperPrivateAPI::Get(GetProfile())->GetLastUnpackedDirectory(),
1205      select_title,
1206      info,
1207      file_type_index);
1208  return result;
1209}
1210
1211void DeveloperPrivateChoosePathFunction::FileSelected(
1212    const base::FilePath& path) {
1213  SetResult(new base::StringValue(UTF16ToUTF8(path.LossyDisplayName())));
1214  SendResponse(true);
1215  Release();
1216}
1217
1218void DeveloperPrivateChoosePathFunction::FileSelectionCanceled() {
1219  SendResponse(false);
1220  Release();
1221}
1222
1223DeveloperPrivateChoosePathFunction::~DeveloperPrivateChoosePathFunction() {}
1224
1225bool DeveloperPrivateGetStringsFunction::RunImpl() {
1226  base::DictionaryValue* dict = new base::DictionaryValue();
1227  SetResult(dict);
1228
1229  webui::SetFontAndTextDirection(dict);
1230
1231  #define   SET_STRING(id, idr) \
1232    dict->SetString(id, l10n_util::GetStringUTF16(idr))
1233  SET_STRING("extensionSettings", IDS_MANAGE_EXTENSIONS_SETTING_WINDOWS_TITLE);
1234
1235  SET_STRING("appsDevtoolSearch", IDS_APPS_DEVTOOL_SEARCH);
1236  SET_STRING("appsDevtoolApps", IDS_APPS_DEVTOOL_APPS_INSTALLED);
1237  SET_STRING("appsDevtoolExtensions", IDS_APPS_DEVTOOL_EXTENSIONS_INSTALLED);
1238  SET_STRING("appsDevtoolNoExtensions", IDS_EXTENSIONS_NONE_INSTALLED);
1239  SET_STRING("appsDevtoolUnpacked", IDS_APPS_DEVTOOL_UNPACKED_INSTALLED);
1240  SET_STRING("appsDevtoolInstalled", IDS_APPS_DEVTOOL_INSTALLED);
1241  SET_STRING("appsDevtoolNoPackedApps", IDS_APPS_DEVTOOL_NO_PACKED_APPS);
1242  SET_STRING("appsDevtoolNoUnpackedApps", IDS_APPS_DEVTOOL_NO_UNPACKED_APPS);
1243  SET_STRING("appsDevtoolNoPackedExtensions",
1244      IDS_APPS_DEVTOOL_NO_PACKED_EXTENSIONS);
1245  SET_STRING("appsDevtoolNoUnpackedExtensions",
1246      IDS_APPS_DEVTOOL_NO_UNPACKED_EXTENSIONS);
1247  SET_STRING("appsDevtoolUpdating", IDS_APPS_DEVTOOL_UPDATING);
1248  SET_STRING("extensionSettingsGetMoreExtensions", IDS_GET_MORE_EXTENSIONS);
1249  SET_STRING("extensionSettingsExtensionId", IDS_EXTENSIONS_ID);
1250  SET_STRING("extensionSettingsExtensionPath", IDS_EXTENSIONS_PATH);
1251  SET_STRING("extensionSettingsInspectViews", IDS_EXTENSIONS_INSPECT_VIEWS);
1252  SET_STRING("extensionSettingsInstallWarnings",
1253             IDS_EXTENSIONS_INSTALL_WARNINGS);
1254  SET_STRING("viewIncognito", IDS_EXTENSIONS_VIEW_INCOGNITO);
1255  SET_STRING("viewInactive", IDS_EXTENSIONS_VIEW_INACTIVE);
1256  SET_STRING("backgroundPage", IDS_EXTENSIONS_BACKGROUND_PAGE);
1257  SET_STRING("extensionSettingsEnable", IDS_EXTENSIONS_ENABLE);
1258  SET_STRING("extensionSettingsEnabled", IDS_EXTENSIONS_ENABLED);
1259  SET_STRING("extensionSettingsRemove", IDS_EXTENSIONS_REMOVE);
1260  SET_STRING("extensionSettingsEnableIncognito",
1261             IDS_EXTENSIONS_ENABLE_INCOGNITO);
1262  SET_STRING("extensionSettingsAllowFileAccess",
1263             IDS_EXTENSIONS_ALLOW_FILE_ACCESS);
1264  SET_STRING("extensionSettingsReloadTerminated",
1265             IDS_EXTENSIONS_RELOAD_TERMINATED);
1266  SET_STRING("extensionSettingsReloadUnpacked",
1267             IDS_APPS_DEV_TOOLS_RELOAD_UNPACKED);
1268  SET_STRING("extensionSettingsLaunch", IDS_EXTENSIONS_LAUNCH);
1269  SET_STRING("extensionSettingsOptions", IDS_EXTENSIONS_OPTIONS_LINK);
1270  SET_STRING("extensionSettingsPermissions", IDS_EXTENSIONS_PERMISSIONS_LINK);
1271  SET_STRING("extensionSettingsVisitWebsite", IDS_EXTENSIONS_VISIT_WEBSITE);
1272  SET_STRING("extensionSettingsVisitWebStore", IDS_EXTENSIONS_VISIT_WEBSTORE);
1273  SET_STRING("extensionSettingsPolicyControlled",
1274             IDS_EXTENSIONS_POLICY_CONTROLLED);
1275  SET_STRING("extensionSettingsManagedMode",
1276             IDS_EXTENSIONS_LOCKED_MANAGED_USER);
1277  SET_STRING("extensionSettingsShowButton", IDS_EXTENSIONS_SHOW_BUTTON);
1278  SET_STRING("appsDevtoolLoadUnpackedButton",
1279             IDS_APPS_DEVTOOL_LOAD_UNPACKED_BUTTON);
1280  SET_STRING("appsDevtoolPackButton", IDS_APPS_DEVTOOL_PACK_BUTTON);
1281  SET_STRING("extensionSettingsCommandsLink",
1282             IDS_EXTENSIONS_COMMANDS_CONFIGURE);
1283  SET_STRING("appsDevtoolUpdateButton", IDS_APPS_DEVTOOL_UPDATE_BUTTON);
1284  SET_STRING("extensionSettingsWarningsTitle", IDS_EXTENSION_WARNINGS_TITLE);
1285  SET_STRING("extensionSettingsShowDetails", IDS_EXTENSIONS_SHOW_DETAILS);
1286  SET_STRING("extensionSettingsHideDetails", IDS_EXTENSIONS_HIDE_DETAILS);
1287  SET_STRING("extensionUninstall", IDS_EXTENSIONS_UNINSTALL);
1288  SET_STRING("extensionsPermissionsHeading",
1289             IDS_EXTENSIONS_PERMISSIONS_HEADING);
1290  SET_STRING("extensionsPermissionsClose", IDS_EXTENSIONS_PERMISSIONS_CLOSE);
1291  SET_STRING("extensionDisabled", IDS_EXTENSIONS_DISABLED);
1292  SET_STRING("extensionSettingsShowLogsButton", IDS_EXTENSIONS_SHOW_LOGS);
1293  SET_STRING("extensionSettingsMoreDetailsButton", IDS_EXTENSIONS_MORE_DETAILS);
1294  SET_STRING("extensionSettingsVersion", IDS_EXTENSIONS_VERSION);
1295  SET_STRING("extensionSettingsDelete", IDS_EXTENSIONS_ADT_DELETE);
1296  SET_STRING("extensionSettingsPack", IDS_EXTENSIONS_PACK);
1297
1298// Pack Extension strings
1299  SET_STRING("packExtensionOverlay", IDS_EXTENSION_PACK_DIALOG_TITLE);
1300  SET_STRING("packExtensionHeading", IDS_EXTENSION_ADT_PACK_DIALOG_HEADING);
1301  SET_STRING("packButton", IDS_EXTENSION_ADT_PACK_BUTTON);
1302  SET_STRING("ok", IDS_OK);
1303  SET_STRING("cancel", IDS_CANCEL);
1304  SET_STRING("packExtensionRootDir",
1305     IDS_EXTENSION_PACK_DIALOG_ROOT_DIRECTORY_LABEL);
1306  SET_STRING("packExtensionPrivateKey",
1307     IDS_EXTENSION_PACK_DIALOG_PRIVATE_KEY_LABEL);
1308  SET_STRING("packExtensionBrowseButton", IDS_EXTENSION_PACK_DIALOG_BROWSE);
1309  SET_STRING("packExtensionProceedAnyway", IDS_EXTENSION_PROCEED_ANYWAY);
1310  SET_STRING("packExtensionWarningTitle", IDS_EXTENSION_PACK_WARNING_TITLE);
1311  SET_STRING("packExtensionErrorTitle", IDS_EXTENSION_PACK_ERROR_TITLE);
1312  SET_STRING("packAppOverlay", IDS_EXTENSION_PACK_APP_DIALOG_TITLE);
1313  SET_STRING("packAppHeading", IDS_EXTENSION_ADT_PACK_APP_DIALOG_HEADING);
1314
1315// Delete confirmation dialog.
1316  SET_STRING("deleteConfirmationDeleteButton",
1317      IDS_APPS_DEVTOOL_DELETE_CONFIRMATION_BUTTON);
1318  SET_STRING("deleteConfirmationTitle",
1319      IDS_APPS_DEVTOOL_DELETE_CONFIRMATION_TITLE);
1320  SET_STRING("deleteConfirmationMessageApp",
1321      IDS_APPS_DEVTOOL_DELETE_CONFIRMATION_MESSAGE_APP);
1322  SET_STRING("deleteConfirmationMessageExtension",
1323      IDS_APPS_DEVTOOL_DELETE_CONFIRMATION_MESSAGE_EXTENSION);
1324
1325// Dialog when profile is managed.
1326  SET_STRING("managedProfileDialogCloseButton",
1327      IDS_APPS_DEVTOOL_MANAGED_PROFILE_DIALOG_CLOSE_BUTTON);
1328  SET_STRING("managedProfileDialogTitle",
1329      IDS_APPS_DEVTOOL_MANAGED_PROFILE_DIALOG_TITLE);
1330  SET_STRING("managedProfileDialogDescription",
1331      IDS_APPS_DEVTOOL_MANAGED_PROFILE_DIALOG_DESCRIPTION);
1332
1333  #undef   SET_STRING
1334  return true;
1335}
1336
1337DeveloperPrivateGetStringsFunction::~DeveloperPrivateGetStringsFunction() {}
1338
1339bool DeveloperPrivateIsProfileManagedFunction::RunImpl() {
1340  SetResult(new base::FundamentalValue(GetProfile()->IsManaged()));
1341  return true;
1342}
1343
1344DeveloperPrivateIsProfileManagedFunction::
1345    ~DeveloperPrivateIsProfileManagedFunction() {
1346}
1347
1348} // namespace api
1349
1350} // namespace extensions
1351