summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordpolukhin@chromium.org <dpolukhin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-10-04 03:41:04 +0000
committerdpolukhin@chromium.org <dpolukhin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-10-04 03:41:04 +0000
commitaa5a547a89c09639881232912a95a7428ed81272 (patch)
treebf49bf0026aa88aba634913005289a75039a2d32
parent065cd860161f3e90f7467260b15e150393c22d81 (diff)
downloadchromium_src-aa5a547a89c09639881232912a95a7428ed81272.zip
chromium_src-aa5a547a89c09639881232912a95a7428ed81272.tar.gz
chromium_src-aa5a547a89c09639881232912a95a7428ed81272.tar.bz2
Add first run prompt fot OEM default apps to acknowledge app permissions
BUG=296393 TEST=manual Review URL: https://codereview.chromium.org/25769004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@226946 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/app/generated_resources.grd6
-rw-r--r--chrome/browser/extensions/extension_browsertest.cc18
-rw-r--r--chrome/browser/extensions/extension_browsertest.h15
-rw-r--r--chrome/browser/extensions/extension_disabled_ui_browsertest.cc62
-rw-r--r--chrome/browser/extensions/extension_install_prompt.cc23
-rw-r--r--chrome/browser/extensions/extension_install_prompt.h8
-rw-r--r--chrome/browser/extensions/extension_service.cc13
-rw-r--r--chrome/browser/extensions/extension_service.h7
-rw-r--r--chrome/browser/extensions/extension_service_unittest.cc15
-rw-r--r--chrome/browser/extensions/external_provider_impl.cc8
-rw-r--r--chrome/browser/extensions/external_provider_impl.h1
-rw-r--r--chrome/browser/ui/app_list/extension_app_item.cc4
-rw-r--r--chrome/browser/ui/extensions/extension_enable_flow.cc7
-rw-r--r--chrome/browser/ui/views/extensions/extension_install_dialog_view.cc17
-rw-r--r--chrome/common/extensions/extension.h12
-rw-r--r--chrome/common/extensions/permissions/permissions_data.cc3
16 files changed, 200 insertions, 19 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 1e49b36..7e0084b 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -4934,6 +4934,9 @@ Keep your key file in a safe place. You will need it to create new versions of y
<message name="IDS_EXTENSION_PROMPT_PERMISSIONS_CLEAR_RETAINED_FILES_BUTTON" desc="Text for the Revoke File Access button on the extension permissions prompt">
Revoke File Access
</message>
+ <message name="IDS_EXTENSION_PROMPT_FIRST_RUN_ACCEPT_BUTTON" desc="Text for the allow button on the first run promopt to accept permissions and launch app">
+ Accept and open
+ </message>
<message name="IDS_EXTENSION_WEB_STORE_TITLE" desc="Text for the Chrome Web Store">
Chrome Web Store
</message>
@@ -5024,6 +5027,9 @@ Keep your key file in a safe place. You will need it to create new versions of y
<message name="IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_ABORT_BUTTON" desc="Button on the external install prompt to remove an extension installed by a third party.">
Remove from Chrome
</message>
+ <message name="IDS_EXTENSION_PROMPT_FIRST_RUN_DECLINE_BUTTON" desc="Button on the first run dialog to remove an app installed by OEM.">
+ Remove app
+ </message>
<message name="IDS_EXTENSIONS_DISABLED" desc="(Disabled) label next to the application name when the application is disabled.">
(Disabled)
</message>
diff --git a/chrome/browser/extensions/extension_browsertest.cc b/chrome/browser/extensions/extension_browsertest.cc
index 8c6313e..47d6a24 100644
--- a/chrome/browser/extensions/extension_browsertest.cc
+++ b/chrome/browser/extensions/extension_browsertest.cc
@@ -363,7 +363,7 @@ const Extension* ExtensionBrowserTest::UpdateExtensionWaitForIdle(
expected_change,
Manifest::INTERNAL,
browser(),
- false,
+ Extension::NO_FLAGS,
true);
}
@@ -376,7 +376,7 @@ const Extension* ExtensionBrowserTest::InstallExtensionFromWebstore(
expected_change,
Manifest::INTERNAL,
browser(),
- true,
+ Extension::FROM_WEBSTORE,
false);
}
@@ -386,7 +386,7 @@ const Extension* ExtensionBrowserTest::InstallOrUpdateExtension(
InstallUIType ui_type,
int expected_change) {
return InstallOrUpdateExtension(id, path, ui_type, expected_change,
- Manifest::INTERNAL, browser(), false, false);
+ Manifest::INTERNAL, browser(), Extension::NO_FLAGS, false);
}
const Extension* ExtensionBrowserTest::InstallOrUpdateExtension(
@@ -395,9 +395,9 @@ const Extension* ExtensionBrowserTest::InstallOrUpdateExtension(
InstallUIType ui_type,
int expected_change,
Browser* browser,
- bool from_webstore) {
+ Extension::InitFromValueFlags creation_flags) {
return InstallOrUpdateExtension(id, path, ui_type, expected_change,
- Manifest::INTERNAL, browser, from_webstore,
+ Manifest::INTERNAL, browser, creation_flags,
false);
}
@@ -408,7 +408,7 @@ const Extension* ExtensionBrowserTest::InstallOrUpdateExtension(
int expected_change,
Manifest::Location install_source) {
return InstallOrUpdateExtension(id, path, ui_type, expected_change,
- install_source, browser(), false, false);
+ install_source, browser(), Extension::NO_FLAGS, false);
}
const Extension* ExtensionBrowserTest::InstallOrUpdateExtension(
@@ -418,7 +418,7 @@ const Extension* ExtensionBrowserTest::InstallOrUpdateExtension(
int expected_change,
Manifest::Location install_source,
Browser* browser,
- bool from_webstore,
+ Extension::InitFromValueFlags creation_flags,
bool wait_for_idle) {
ExtensionService* service = profile()->GetExtensionService();
service->set_show_extensions_prompts(false);
@@ -448,10 +448,10 @@ const Extension* ExtensionBrowserTest::InstallOrUpdateExtension(
scoped_refptr<extensions::CrxInstaller> installer(
extensions::CrxInstaller::Create(service, install_ui.Pass()));
installer->set_expected_id(id);
- installer->set_is_gallery_install(from_webstore);
+ installer->set_creation_flags(creation_flags);
installer->set_install_source(install_source);
installer->set_install_wait_for_idle(wait_for_idle);
- if (!from_webstore) {
+ if (!installer->is_gallery_install()) {
installer->set_off_store_install_allow_reason(
extensions::CrxInstaller::OffStoreInstallAllowedInTest);
}
diff --git a/chrome/browser/extensions/extension_browsertest.h b/chrome/browser/extensions/extension_browsertest.h
index 5962d33..ad127c3 100644
--- a/chrome/browser/extensions/extension_browsertest.h
+++ b/chrome/browser/extensions/extension_browsertest.h
@@ -164,7 +164,16 @@ class ExtensionBrowserTest : virtual public InProcessBrowserTest,
INSTALL_UI_TYPE_AUTO_CONFIRM,
expected_change,
browser,
- false);
+ extensions::Extension::NO_FLAGS);
+ }
+
+ const extensions::Extension* InstallExtensionWithSourceAndFlags(
+ const base::FilePath& path,
+ int expected_change,
+ extensions::Manifest::Location install_source,
+ extensions::Extension::InitFromValueFlags creation_flags) {
+ return InstallOrUpdateExtension(std::string(), path, INSTALL_UI_TYPE_NONE,
+ expected_change, install_source, browser(), creation_flags, false);
}
// Begins install process but simulates a user cancel.
@@ -275,7 +284,7 @@ class ExtensionBrowserTest : virtual public InProcessBrowserTest,
InstallUIType ui_type,
int expected_change,
Browser* browser,
- bool from_webstore);
+ extensions::Extension::InitFromValueFlags creation_flags);
const extensions::Extension* InstallOrUpdateExtension(
const std::string& id,
const base::FilePath& path,
@@ -289,7 +298,7 @@ class ExtensionBrowserTest : virtual public InProcessBrowserTest,
int expected_change,
extensions::Manifest::Location install_source,
Browser* browser,
- bool from_webstore,
+ extensions::Extension::InitFromValueFlags creation_flags,
bool wait_for_idle);
// Wait for a notification of the specified type to be sent.
diff --git a/chrome/browser/extensions/extension_disabled_ui_browsertest.cc b/chrome/browser/extensions/extension_disabled_ui_browsertest.cc
index 8f20cfb..d2ca1c8 100644
--- a/chrome/browser/extensions/extension_disabled_ui_browsertest.cc
+++ b/chrome/browser/extensions/extension_disabled_ui_browsertest.cc
@@ -24,6 +24,13 @@
#include "net/url_request/url_fetcher.h"
using extensions::Extension;
+using extensions::Manifest;
+
+namespace {
+
+const char kTestExtensionId[] = "pgdpcfcocojkjfbgpiianjngphoopgmo";
+
+}
class ExtensionDisabledGlobalErrorTest : public ExtensionBrowserTest {
protected:
@@ -222,3 +229,58 @@ IN_PROC_BROWSER_TEST_F(ExtensionDisabledGlobalErrorTest,
service_->extension_prefs()->GetDisableReasons(extension_id));
EXPECT_TRUE(GetExtensionDisabledGlobalError());
}
+
+// Tests that default app with user consent are not enabled after install.
+IN_PROC_BROWSER_TEST_F(ExtensionDisabledGlobalErrorTest, DefaultWithConsent) {
+ InstallExtensionWithSourceAndFlags(path_v1_, 0, Manifest::EXTERNAL_PREF,
+ Extension::InitFromValueFlags(Extension::FROM_WEBSTORE |
+ Extension::WAS_INSTALLED_BY_DEFAULT |
+ Extension::REQUIRE_PERMISSIONS_CONSENT));
+ ASSERT_FALSE(GetExtensionDisabledGlobalError());
+
+ // Should be disabled with no error after install.
+ const Extension* extension =
+ service_->GetExtensionById(kTestExtensionId, true);
+ ASSERT_TRUE(extension);
+ EXPECT_EQ("1", extension->VersionString());
+ EXPECT_FALSE(service_->IsExtensionEnabled(kTestExtensionId));
+ EXPECT_EQ(Extension::DISABLE_PERMISSIONS_CONSENT,
+ service_->extension_prefs()->GetDisableReasons(kTestExtensionId));
+
+ // Update to v2 with more permissions, extension should stay disabled with
+ // the same reason, no error message.
+ UpdateIncreasingPermissionExtension(extension, path_v2_, 0);
+ extension = service_->GetExtensionById(kTestExtensionId, true);
+ ASSERT_TRUE(extension);
+ EXPECT_EQ("2", extension->VersionString());
+ EXPECT_FALSE(service_->IsExtensionEnabled(kTestExtensionId));
+ EXPECT_EQ(Extension::DISABLE_PERMISSIONS_CONSENT |
+ Extension::DISABLE_PERMISSIONS_INCREASE,
+ service_->extension_prefs()->GetDisableReasons(kTestExtensionId));
+
+ service_->GrantPermissionsAndEnableExtension(extension);
+ EXPECT_TRUE(service_->IsExtensionEnabled(kTestExtensionId));
+
+ // Update to v3 with more permissions, should be disabled with error.
+ UpdateIncreasingPermissionExtension(extension, path_v3_, -1);
+ extension = service_->GetExtensionById(kTestExtensionId, true);
+ ASSERT_TRUE(extension);
+ EXPECT_EQ("3", extension->VersionString());
+ ASSERT_TRUE(GetExtensionDisabledGlobalError());
+ EXPECT_FALSE(service_->IsExtensionEnabled(kTestExtensionId));
+ EXPECT_EQ(Extension::DISABLE_PERMISSIONS_INCREASE,
+ service_->extension_prefs()->GetDisableReasons(kTestExtensionId));
+
+ // Enabled extension with granting permissions.
+ extension = UpdateExtension(kTestExtensionId, path_v3_, 0);
+ extension = service_->GetExtensionById(kTestExtensionId, true);
+ ASSERT_TRUE(extension);
+ service_->GrantPermissionsAndEnableExtension(extension);
+ EXPECT_TRUE(service_->IsExtensionEnabled(kTestExtensionId));
+
+ // Update again to v3 with the same permissions.
+ extension = UpdateExtension(kTestExtensionId, path_v3_, 0);
+ ASSERT_TRUE(extension);
+ ASSERT_FALSE(GetExtensionDisabledGlobalError());
+ EXPECT_TRUE(service_->IsExtensionEnabled(kTestExtensionId));
+}
diff --git a/chrome/browser/extensions/extension_install_prompt.cc b/chrome/browser/extensions/extension_install_prompt.cc
index e4a08aa..1eb7171 100644
--- a/chrome/browser/extensions/extension_install_prompt.cc
+++ b/chrome/browser/extensions/extension_install_prompt.cc
@@ -59,6 +59,7 @@ static const int kTitleIds[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
IDS_EXTENSION_PERMISSIONS_PROMPT_TITLE,
IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_TITLE,
IDS_EXTENSION_POST_INSTALL_PERMISSIONS_PROMPT_TITLE,
+ 0, // The prompt should be extension description.
};
static const int kHeadingIds[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
IDS_EXTENSION_INSTALL_PROMPT_HEADING,
@@ -68,6 +69,7 @@ static const int kHeadingIds[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
IDS_EXTENSION_PERMISSIONS_PROMPT_HEADING,
0, // External installs use different strings for extensions/apps.
IDS_EXTENSION_POST_INSTALL_PERMISSIONS_PROMPT_HEADING,
+ 0, // First run dialog use the extension name.
};
static const int kButtons[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL,
@@ -77,6 +79,7 @@ static const int kButtons[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL,
ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL,
ui::DIALOG_BUTTON_CANCEL,
+ ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL,
};
static const int kAcceptButtonIds[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
IDS_EXTENSION_PROMPT_INSTALL_BUTTON,
@@ -86,6 +89,7 @@ static const int kAcceptButtonIds[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
IDS_EXTENSION_PROMPT_PERMISSIONS_BUTTON,
0, // External installs use different strings for extensions/apps.
IDS_EXTENSION_PROMPT_PERMISSIONS_CLEAR_RETAINED_FILES_BUTTON,
+ IDS_EXTENSION_PROMPT_FIRST_RUN_ACCEPT_BUTTON
};
static const int kAbortButtonIds[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
0, // These all use the platform's default cancel label.
@@ -95,6 +99,7 @@ static const int kAbortButtonIds[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
IDS_EXTENSION_PROMPT_PERMISSIONS_ABORT_BUTTON,
IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_ABORT_BUTTON,
IDS_CLOSE,
+ IDS_EXTENSION_PROMPT_FIRST_RUN_DECLINE_BUTTON
};
static const int kPermissionsHeaderIds[
ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
@@ -105,6 +110,7 @@ static const int kPermissionsHeaderIds[
IDS_EXTENSION_PROMPT_WANTS_ACCESS_TO,
IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO,
IDS_EXTENSION_PROMPT_CAN_ACCESS,
+ IDS_EXTENSION_PROMPT_CAN_ACCESS,
};
static const int kOAuthHeaderIds[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
IDS_EXTENSION_PROMPT_OAUTH_HEADER,
@@ -114,6 +120,7 @@ static const int kOAuthHeaderIds[ExtensionInstallPrompt::NUM_PROMPT_TYPES] = {
IDS_EXTENSION_PROMPT_OAUTH_PERMISSIONS_HEADER,
0,
0,
+ IDS_EXTENSION_PROMPT_OAUTH_HEADER,
};
// Size of extension icon in top left of dialog.
@@ -270,6 +277,8 @@ string16 ExtensionInstallPrompt::Prompt::GetDialogTitle() const {
} else if (type_ == EXTERNAL_INSTALL_PROMPT) {
return l10n_util::GetStringFUTF16(
resource_id, UTF8ToUTF16(extension_->name()));
+ } else if (type_ == DEFAULT_INSTALL_FIRST_RUN_PROMPT) {
+ return UTF8ToUTF16(extension_->name());
}
return l10n_util::GetStringUTF16(resource_id);
@@ -289,6 +298,8 @@ string16 ExtensionInstallPrompt::Prompt::GetHeading() const {
else
resource_id = IDS_EXTENSION_EXTERNAL_INSTALL_PROMPT_HEADING_EXTENSION;
return l10n_util::GetStringUTF16(resource_id);
+ } else if (type_ == DEFAULT_INSTALL_FIRST_RUN_PROMPT) {
+ return UTF8ToUTF16(extension_->description());
} else {
return l10n_util::GetStringFUTF16(
kHeadingIds[type_], UTF8ToUTF16(extension_->name()));
@@ -623,6 +634,17 @@ void ExtensionInstallPrompt::ConfirmReEnable(Delegate* delegate,
LoadImageIfNeeded();
}
+void ExtensionInstallPrompt::ConfirmDefaultInstallFirstRun(
+ Delegate* delegate,
+ const Extension* extension) {
+ DCHECK(ui_loop_ == base::MessageLoop::current());
+ extension_ = extension;
+ permissions_ = extension->GetActivePermissions();
+ delegate_ = delegate;
+ prompt_.set_type(DEFAULT_INSTALL_FIRST_RUN_PROMPT);
+ LoadImageIfNeeded();
+}
+
void ExtensionInstallPrompt::ConfirmExternalInstall(
Delegate* delegate,
const Extension* extension,
@@ -791,6 +813,7 @@ void ExtensionInstallPrompt::ShowConfirmation() {
switch (prompt_.type()) {
case PERMISSIONS_PROMPT:
case RE_ENABLE_PROMPT:
+ case DEFAULT_INSTALL_FIRST_RUN_PROMPT:
case INLINE_INSTALL_PROMPT:
case EXTERNAL_INSTALL_PROMPT:
case INSTALL_PROMPT:
diff --git a/chrome/browser/extensions/extension_install_prompt.h b/chrome/browser/extensions/extension_install_prompt.h
index a8ac211..c59f97d 100644
--- a/chrome/browser/extensions/extension_install_prompt.h
+++ b/chrome/browser/extensions/extension_install_prompt.h
@@ -60,6 +60,7 @@ class ExtensionInstallPrompt
PERMISSIONS_PROMPT,
EXTERNAL_INSTALL_PROMPT,
POST_INSTALL_PERMISSIONS_PROMPT,
+ DEFAULT_INSTALL_FIRST_RUN_PROMPT,
NUM_PROMPT_TYPES
};
@@ -305,6 +306,13 @@ class ExtensionInstallPrompt
virtual void ConfirmReEnable(Delegate* delegate,
const extensions::Extension* extension);
+ // This is called by the app handler launcher to verify whether the app
+ // should be launched first time. This is declared virtual for testing.
+ //
+ // We *MUST* eventually call either Proceed() or Abort() on |delegate|.
+ virtual void ConfirmDefaultInstallFirstRun(Delegate* delegate,
+ const extensions::Extension* extension);
+
// This is called by the external install alert UI to verify whether the
// extension should be enabled (external extensions are installed disabled).
//
diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc
index 23f684e..eddbf5c 100644
--- a/chrome/browser/extensions/extension_service.cc
+++ b/chrome/browser/extensions/extension_service.cc
@@ -937,6 +937,13 @@ bool ExtensionService::IsExtensionEnabledForLauncher(
!GetTerminatedExtension(extension_id);
}
+bool ExtensionService::DoesExtensionRequirePermissionConsent(
+ const std::string& extension_id) const {
+ return extension_prefs_->IsExtensionDisabled(extension_id) &&
+ (extension_prefs_->GetDisableReasons(extension_id) &
+ Extension::DISABLE_PERMISSIONS_CONSENT);
+}
+
void ExtensionService::EnableExtension(const std::string& extension_id) {
CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
@@ -2242,7 +2249,8 @@ void ExtensionService::CheckPermissionsIncrease(const Extension* extension,
int disable_reasons = extension_prefs_->GetDisableReasons(extension->id());
bool auto_grant_permission =
- (!is_extension_installed && extension->was_installed_by_default()) ||
+ (!is_extension_installed && extension->was_installed_by_default() &&
+ !extension->requires_permissions_consent()) ||
chrome::IsRunningInForcedAppMode();
// Silently grant all active permissions to default apps only on install.
// After install they should behave like other apps.
@@ -2291,6 +2299,9 @@ void ExtensionService::CheckPermissionsIncrease(const Extension* extension,
disable_reasons |= Extension::DISABLE_USER_ACTION;
}
disable_reasons &= ~Extension::DISABLE_UNKNOWN_FROM_SYNC;
+ } else if (extension->requires_permissions_consent()) {
+ disable_reasons |= Extension::DISABLE_PERMISSIONS_CONSENT;
+ extension_prefs_->SetExtensionState(extension->id(), Extension::DISABLED);
}
// Extension has changed permissions significantly. Disable it. A
diff --git a/chrome/browser/extensions/extension_service.h b/chrome/browser/extensions/extension_service.h
index 92e0119..603849d 100644
--- a/chrome/browser/extensions/extension_service.h
+++ b/chrome/browser/extensions/extension_service.h
@@ -309,9 +309,14 @@ class ExtensionService
virtual bool IsExternalExtensionUninstalled(
const std::string& extension_id) const OVERRIDE;
- // Whether the extension should show as enabled state in launcher.
+ // Whether the extension should be enabled for running.
bool IsExtensionEnabledForLauncher(const std::string& extension_id) const;
+ // Whether the extension is waiting for permission consent. Such extensions
+ // technically disabled (can't be launched) but UI shows them as normal.
+ bool DoesExtensionRequirePermissionConsent(
+ const std::string& extension_id) const;
+
// Enables the extension. If the extension is already enabled, does
// nothing.
virtual void EnableExtension(const std::string& extension_id);
diff --git a/chrome/browser/extensions/extension_service_unittest.cc b/chrome/browser/extensions/extension_service_unittest.cc
index aca590f..4864187 100644
--- a/chrome/browser/extensions/extension_service_unittest.cc
+++ b/chrome/browser/extensions/extension_service_unittest.cc
@@ -4916,6 +4916,21 @@ TEST_F(ExtensionServiceTest, ExternalPrefProvider) {
" }"
"}";
EXPECT_EQ(1, from_webstore_visitor.Visit(json_data));
+
+ // Test require_permissions_consent.
+ MockProviderVisitor permissions_consent_visitor(
+ base_path, Extension::REQUIRE_PERMISSIONS_CONSENT);
+ json_data =
+ "{"
+ " \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\": {"
+ " \"external_crx\": \"RandomExtension.crx\","
+ " \"external_version\": \"1.0\","
+ " \"require_permissions_consent\": true"
+ " }"
+ "}";
+ {
+ EXPECT_EQ(1, permissions_consent_visitor.Visit(json_data));
+ }
}
// Test loading good extensions from the profile directory.
diff --git a/chrome/browser/extensions/external_provider_impl.cc b/chrome/browser/extensions/external_provider_impl.cc
index 78b1417..c2d2851 100644
--- a/chrome/browser/extensions/external_provider_impl.cc
+++ b/chrome/browser/extensions/external_provider_impl.cc
@@ -58,6 +58,8 @@ const char ExternalProviderImpl::kSupportedLocales[] = "supported_locales";
const char ExternalProviderImpl::kIsBookmarkApp[] = "is_bookmark_app";
const char ExternalProviderImpl::kIsFromWebstore[] = "is_from_webstore";
const char ExternalProviderImpl::kKeepIfPresent[] = "keep_if_present";
+const char ExternalProviderImpl::kRequirePermissionsConsent[] =
+ "require_permissions_consent";
ExternalProviderImpl::ExternalProviderImpl(VisitorInterface* service,
ExternalLoader* loader,
@@ -214,6 +216,12 @@ void ExternalProviderImpl::SetPrefs(base::DictionaryValue* prefs) {
continue;
}
}
+ bool require_permissions_consent;
+ if (extension->GetBoolean(kRequirePermissionsConsent,
+ &require_permissions_consent) &&
+ require_permissions_consent) {
+ creation_flags |= Extension::REQUIRE_PERMISSIONS_CONSENT;
+ }
if (has_external_crx) {
if (crx_location_ == Manifest::INVALID_LOCATION) {
diff --git a/chrome/browser/extensions/external_provider_impl.h b/chrome/browser/extensions/external_provider_impl.h
index 8375826..991d0bb 100644
--- a/chrome/browser/extensions/external_provider_impl.h
+++ b/chrome/browser/extensions/external_provider_impl.h
@@ -73,6 +73,7 @@ class ExternalProviderImpl : public ExternalProviderInterface {
static const char kIsBookmarkApp[];
static const char kIsFromWebstore[];
static const char kKeepIfPresent[];
+ static const char kRequirePermissionsConsent[];
void set_auto_acknowledge(bool auto_acknowledge) {
auto_acknowledge_ = auto_acknowledge;
diff --git a/chrome/browser/ui/app_list/extension_app_item.cc b/chrome/browser/ui/app_list/extension_app_item.cc
index 6050cb7..1680086 100644
--- a/chrome/browser/ui/app_list/extension_app_item.cc
+++ b/chrome/browser/ui/app_list/extension_app_item.cc
@@ -171,7 +171,9 @@ void ExtensionAppItem::UpdateIcon() {
const ExtensionService* service =
extensions::ExtensionSystem::Get(profile_)->extension_service();
- const bool enabled = service->IsExtensionEnabledForLauncher(extension_id_);
+ // If app waits for permission confirmation, don't show it disabled in UI.
+ const bool enabled = service->IsExtensionEnabledForLauncher(extension_id_) ||
+ service->DoesExtensionRequirePermissionConsent(extension_id_);
if (!enabled) {
const color_utils::HSL shift = {-1, 0, 0.6};
icon = gfx::ImageSkiaOperations::CreateHSLShiftedImage(icon, shift);
diff --git a/chrome/browser/ui/extensions/extension_enable_flow.cc b/chrome/browser/ui/extensions/extension_enable_flow.cc
index 2ec1f98..3e27e0c 100644
--- a/chrome/browser/ui/extensions/extension_enable_flow.cc
+++ b/chrome/browser/ui/extensions/extension_enable_flow.cc
@@ -9,6 +9,7 @@
#include "chrome/browser/extensions/extension_system.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/extensions/extension_enable_flow_delegate.h"
+#include "chrome/common/extensions/permissions/permission_set.h"
#include "content/public/browser/notification_details.h"
#include "content/public/browser/notification_source.h"
@@ -94,7 +95,11 @@ void ExtensionEnableFlow::CheckPermissionAndMaybePromptUser() {
}
CreatePrompt();
- prompt_->ConfirmReEnable(this, extension);
+ int disable_reasons = extension_prefs->GetDisableReasons(extension->id());
+ if (disable_reasons & Extension::DISABLE_PERMISSIONS_CONSENT)
+ prompt_->ConfirmDefaultInstallFirstRun(this, extension);
+ else
+ prompt_->ConfirmReEnable(this, extension);
}
void ExtensionEnableFlow::CreatePrompt() {
diff --git a/chrome/browser/ui/views/extensions/extension_install_dialog_view.cc b/chrome/browser/ui/views/extensions/extension_install_dialog_view.cc
index d4adf07..59a9d04 100644
--- a/chrome/browser/ui/views/extensions/extension_install_dialog_view.cc
+++ b/chrome/browser/ui/views/extensions/extension_install_dialog_view.cc
@@ -135,6 +135,11 @@ class ExtensionInstallDialogView : public views::DialogDelegateView,
return prompt_.type() == ExtensionInstallPrompt::INLINE_INSTALL_PROMPT;
}
+ bool is_first_run() const {
+ return prompt_.type() ==
+ ExtensionInstallPrompt::DEFAULT_INSTALL_FIRST_RUN_PROMPT;
+ }
+
bool is_bundle_install() const {
return prompt_.type() == ExtensionInstallPrompt::BUNDLE_INSTALL_PROMPT;
}
@@ -412,7 +417,10 @@ ExtensionInstallDialogView::ExtensionInstallDialogView(
icon_row_span = 4;
} else if (prompt.ShouldShowPermissions()) {
size_t permission_count = prompt.GetPermissionCount();
- if (permission_count > 0) {
+ if (is_first_run()) {
+ // In first run case we have separator.
+ icon_row_span = 1;
+ } else if (permission_count > 0) {
// Also span the permission header and each of the permission rows (all
// have a padding row above it).
icon_row_span = 3 + permission_count * 2;
@@ -482,7 +490,7 @@ ExtensionInstallDialogView::ExtensionInstallDialogView(
layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
if (prompt.GetPermissionCount() > 0) {
- if (is_inline_install()) {
+ if (is_inline_install() || is_first_run()) {
layout->StartRow(0, column_set_id);
layout->AddView(new views::Separator(views::Separator::HORIZONTAL),
3, 1, views::GridLayout::FILL, views::GridLayout::FILL);
@@ -655,7 +663,10 @@ string16 ExtensionInstallDialogView::GetDialogButtonLabel(
}
int ExtensionInstallDialogView::GetDefaultDialogButton() const {
- return ui::DIALOG_BUTTON_CANCEL;
+ if (is_first_run())
+ return ui::DIALOG_BUTTON_OK;
+ else
+ return ui::DIALOG_BUTTON_CANCEL;
}
bool ExtensionInstallDialogView::Cancel() {
diff --git a/chrome/common/extensions/extension.h b/chrome/common/extensions/extension.h
index 21cd609..3c1067d 100644
--- a/chrome/common/extensions/extension.h
+++ b/chrome/common/extensions/extension.h
@@ -89,6 +89,10 @@ class Extension : public base::RefCountedThreadSafe<Extension> {
DISABLE_UNSUPPORTED_REQUIREMENT = 1 << 3,
DISABLE_SIDELOAD_WIPEOUT = 1 << 4,
DISABLE_UNKNOWN_FROM_SYNC = 1 << 5,
+
+ // Disabled because the user has not yet consented to the permissions,
+ // for instance for a default installed item.
+ DISABLE_PERMISSIONS_CONSENT = 1 << 6,
};
enum InstallType {
@@ -145,6 +149,11 @@ class Extension : public base::RefCountedThreadSafe<Extension> {
// |WAS_INSTALLED_BY_DEFAULT| installed by default when the profile was
// created.
WAS_INSTALLED_BY_DEFAULT = 1 << 7,
+
+ // |REQUIRE_PERMISSIONS_CONSENT| means that user needs to accept permissions
+ // before running the app even if it is marked as |WAS_INSTALLED_BY_DEFAULT|
+ // and |FROM_WEBSTORE|.
+ REQUIRE_PERMISSIONS_CONSENT = 1 << 8,
};
static scoped_refptr<Extension> Create(const base::FilePath& path,
@@ -312,6 +321,9 @@ class Extension : public base::RefCountedThreadSafe<Extension> {
bool was_installed_by_default() const {
return (creation_flags_ & WAS_INSTALLED_BY_DEFAULT) != 0;
}
+ bool requires_permissions_consent() const {
+ return (creation_flags_ & REQUIRE_PERMISSIONS_CONSENT) != 0;
+ }
// App-related.
bool is_app() const;
diff --git a/chrome/common/extensions/permissions/permissions_data.cc b/chrome/common/extensions/permissions/permissions_data.cc
index d9e56ef..a05a2d8 100644
--- a/chrome/common/extensions/permissions/permissions_data.cc
+++ b/chrome/common/extensions/permissions/permissions_data.cc
@@ -391,6 +391,9 @@ const URLPatternSet& PermissionsData::GetEffectiveHostPermissions(
// static
bool PermissionsData::CanSilentlyIncreasePermissions(
const Extension* extension) {
+ if (extension->requires_permissions_consent())
+ return false;
+
return extension->location() != Manifest::INTERNAL;
}