Chromium Code Reviews| Index: chrome/browser/search/hotword_service.cc |
| diff --git a/chrome/browser/search/hotword_service.cc b/chrome/browser/search/hotword_service.cc |
| index 7e67c647ad8d040c6e2421367063ef9a757136e7..0800f2642e81bbd518a9d3d031ec8a23fad19663 100644 |
| --- a/chrome/browser/search/hotword_service.cc |
| +++ b/chrome/browser/search/hotword_service.cc |
| @@ -12,6 +12,9 @@ |
| #include "chrome/browser/browser_process.h" |
| #include "chrome/browser/chrome_notification_types.h" |
| #include "chrome/browser/extensions/extension_service.h" |
| +#include "chrome/browser/extensions/pending_extension_manager.h" |
| +#include "chrome/browser/extensions/updater/extension_updater.h" |
| +#include "chrome/browser/extensions/webstore_startup_installer.h" |
| #include "chrome/browser/plugins/plugin_prefs.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/search/hotword_service_factory.h" |
| @@ -24,6 +27,7 @@ |
| #include "content/public/common/webplugininfo.h" |
| #include "extensions/browser/extension_system.h" |
| #include "extensions/common/extension.h" |
| +#include "extensions/common/one_shot_event.h" |
| #include "grit/generated_resources.h" |
| #include "ui/base/l10n/l10n_util.h" |
| @@ -145,6 +149,18 @@ ExtensionService* GetExtensionService(Profile* profile) { |
| return NULL; |
| } |
| +// static |
| +std::string GetCurrentLocale(Profile* profile) { |
| + std::string locale = |
| +#if defined(OS_CHROMEOS) |
| + // On ChromeOS locale is per-profile. |
| + profile->GetPrefs()->GetString(prefs::kApplicationLocale); |
| +#else |
| + g_browser_process->GetApplicationLocale(); |
| +#endif |
| + return locale; |
| +} |
| + |
| } // namespace |
| namespace hotword_internal { |
| @@ -157,14 +173,8 @@ const char kHotwordUnusablePrefName[] = "hotword.search_enabled"; |
| // static |
| bool HotwordService::DoesHotwordSupportLanguage(Profile* profile) { |
| - std::string locale = |
| -#if defined(OS_CHROMEOS) |
| - // On ChromeOS locale is per-profile. |
| - profile->GetPrefs()->GetString(prefs::kApplicationLocale); |
| -#else |
| - g_browser_process->GetApplicationLocale(); |
| -#endif |
| - std::string normalized_locale = l10n_util::NormalizeLocale(locale); |
| + std::string normalized_locale = |
| + l10n_util::NormalizeLocale(GetCurrentLocale(profile)); |
| StringToLowerASCII(&normalized_locale); |
| for (size_t i = 0; i < arraysize(kSupportedLocales); i++) { |
| @@ -176,8 +186,12 @@ bool HotwordService::DoesHotwordSupportLanguage(Profile* profile) { |
| HotwordService::HotwordService(Profile* profile) |
| : profile_(profile), |
| + extension_registry_observer_(this), |
| client_(NULL), |
| - error_message_(0) { |
| + error_message_(0), |
| + uninstall_pending_(false), |
| + weak_factory_(this) { |
| + extension_registry_observer_.Add(extensions::ExtensionRegistry::Get(profile)); |
| // This will be called during profile initialization which is a good time |
| // to check the user's hotword state. |
| HotwordEnabled enabled_state = UNSET; |
| @@ -203,12 +217,15 @@ HotwordService::HotwordService(Profile* profile) |
| base::Unretained(this))); |
| registrar_.Add(this, |
| - chrome::NOTIFICATION_EXTENSION_INSTALLED_DEPRECATED, |
| - content::Source<Profile>(profile_)); |
| - registrar_.Add(this, |
| chrome::NOTIFICATION_BROWSER_WINDOW_READY, |
| content::NotificationService::AllSources()); |
| + extensions::ExtensionSystem::Get(profile_)->ready().Post( |
| + FROM_HERE, |
| + base::Bind(base::IgnoreResult( |
| + &HotwordService::MaybeUninstallHotwordExtension), |
| + weak_factory_.GetWeakPtr())); |
| + |
| // Clear the old user pref because it became unusable. |
| // TODO(rlp): Remove this code per crbug.com/358789. |
| if (profile_->GetPrefs()->HasPrefPath( |
| @@ -223,25 +240,7 @@ HotwordService::~HotwordService() { |
| void HotwordService::Observe(int type, |
| const content::NotificationSource& source, |
| const content::NotificationDetails& details) { |
| - if (type == chrome::NOTIFICATION_EXTENSION_INSTALLED_DEPRECATED) { |
| - const extensions::Extension* extension = |
| - content::Details<const extensions::InstalledExtensionInfo>(details) |
| - ->extension; |
| - // Disabling the extension automatically on install should only occur |
| - // if the user is in the field trial for auto-install which is gated |
| - // by the IsHotwordAllowed check. |
| - if (IsHotwordAllowed() && |
| - extension->id() == extension_misc::kHotwordExtensionId && |
| - !profile_->GetPrefs()->GetBoolean(prefs::kHotwordSearchEnabled)) { |
| - DisableHotwordExtension(GetExtensionService(profile_)); |
| - // Once the extension is disabled, it will not be enabled until the |
| - // user opts in at which point the pref registrar will take over |
| - // enabling and disabling. |
| - registrar_.Remove(this, |
| - chrome::NOTIFICATION_EXTENSION_INSTALLED_DEPRECATED, |
| - content::Source<Profile>(profile_)); |
| - } |
| - } else if (type == chrome::NOTIFICATION_BROWSER_WINDOW_READY) { |
| + if (type == chrome::NOTIFICATION_BROWSER_WINDOW_READY) { |
| // The microphone monitor must be initialized as the page is loading |
| // so that the state of the microphone is available when the page |
| // loads. The Ok Google Hotword setting will display an error if there |
| @@ -257,6 +256,120 @@ void HotwordService::Observe(int type, |
| } |
| } |
| +void HotwordService::OnExtensionUninstalled( |
| + content::BrowserContext* browser_context, |
| + const extensions::Extension* extension) { |
| + CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
| + |
| + if (extension->id() != extension_misc::kHotwordExtensionId || |
| + profile_ != static_cast<Profile*>(browser_context) || |
|
Yoyo Zhou
2014/06/18 00:33:21
Profile::FromBrowserContext
rpetterson
2014/06/18 02:08:44
Done.
|
| + !GetExtensionService(profile_)) |
| + return; |
| + |
| + // Verify that the extension was uninstalled because of a locale mismatch. |
| + // If that's the case, reinstall and reset the saved locale. |
| + if (!ShouldUninstallHotwordExtension()) |
|
Yoyo Zhou
2014/06/18 00:33:21
Does uninstall_pending_ serve as well here?
rpetterson
2014/06/18 02:08:44
You mean just replace the check ShouldUninstallHot
|
| + return; |
| + |
| + InstallHotwordExtensionFromWebstore(); |
| + SetPreviousLocalePref(); |
| +} |
| + |
| +void HotwordService::InstallHotwordExtensionFromWebstore() { |
| + extensions::WebstoreStandaloneInstaller::Callback callback = |
| + base::Bind(&HotwordService::OnHotwordExtensionInstalled, |
| + base::Unretained(this)); |
| + installer_ = new extensions::WebstoreStartupInstaller( |
|
Yoyo Zhou
2014/06/18 00:33:21
I'm not confident that this is the right choice of
rpetterson
2014/06/18 02:08:44
This is the same one used by ChromeOS to install t
|
| + extension_misc::kHotwordExtensionId, |
| + profile_, |
| + false, |
| + callback); |
| + installer_->BeginInstall(); |
| +} |
| + |
| +void HotwordService::OnExtensionInstalled( |
| + content::BrowserContext* browser_context, |
| + const extensions::Extension* extension) { |
| + |
| + if (extension->id() != extension_misc::kHotwordExtensionId || |
| + profile_ != static_cast<Profile*>(browser_context)) |
| + return; |
| + |
| + // If the previous locale pref has never been set, set it now since |
| + // the extension has been installed. |
| + if (!profile_->GetPrefs()->HasPrefPath(prefs::kHotwordPreviousLanguage)) |
| + SetPreviousLocalePref(); |
| + |
| + // If MaybeUninstallHotwordExtension already triggered an uninstall, we |
| + // don't want to loop and trigger another uninstall-install cycle. |
| + // However, if we arrived her via an uninstall-triggered-install (and in |
| + // that case |uninstall_pending_| will be true) then we know install |
| + // has completed and we can reset |uninstall_pending_|. |
| + if (!uninstall_pending_) |
|
Yoyo Zhou
2014/06/18 00:33:21
What do you think about calling this reinstall_pen
rpetterson
2014/06/18 02:08:44
sgtm. done.
|
| + MaybeUninstallHotwordExtension(); |
| + else |
| + uninstall_pending_ = false; |
| + |
| + // Now that the extension is installed, if the user has not selected |
| + // the preference on, make sure it is turned off. |
| + // |
| + // Disabling the extension automatically on install should only occur |
| + // if the user is in the field trial for auto-install which is gated |
| + // by the IsHotwordAllowed check. The check for IsHotwordAllowed() here |
| + // can be removed once it's known that few people have manually |
| + // installed extension. |
| + if (IsHotwordAllowed() && |
|
Yoyo Zhou
2014/06/18 00:33:21
This check/disable looks repeated from the constru
rpetterson
2014/06/18 02:08:44
Yes, but we have to repeat it because the HotwordS
|
| + !profile_->GetPrefs()->GetBoolean(prefs::kHotwordSearchEnabled)) { |
| + DisableHotwordExtension(GetExtensionService(profile_)); |
| + } |
| +} |
| + |
| +bool HotwordService::MaybeUninstallHotwordExtension() { |
| + CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
| + |
| + ExtensionService* extension_service = GetExtensionService(profile_); |
| + if (!extension_service) |
| + return false; |
| + |
| + const extensions::Extension* extension = extension_service->GetExtensionById( |
| + extension_misc::kHotwordExtensionId, true); |
| + if (!extension) |
| + return false; |
| + |
| + // If the extension is currently pending, return and we'll check again |
| + // after the install is finished. |
| + extensions::PendingExtensionManager* pending_manager = |
| + extension_service->pending_extension_manager(); |
| + if (pending_manager->IsIdPending(extension->id())) |
| + return false; |
| + |
| + // If there is already a pending request from HotwordService, don't try |
| + // to uninstall either. |
| + if (uninstall_pending_) |
| + return false; |
| + |
| + // Check if the current locale matches the previous. If they don't match, |
| + // uninstall the extension. |
| + if (!ShouldUninstallHotwordExtension()) |
| + return false; |
| + |
| + uninstall_pending_ = true; |
| + return UninstallHotwordExtension(extension_service); |
| +} |
| + |
| +bool HotwordService::UninstallHotwordExtension( |
| + ExtensionService* extension_service) { |
| + base::string16 error; |
| + if (!extension_service->UninstallExtension( |
| + extension_misc::kHotwordExtensionId, true, &error)) { |
| + LOG(WARNING) << "Cannot uninstall extension with id " |
| + << extension_misc::kHotwordExtensionId |
| + << ": " << error; |
| + return false; |
| + } |
| + return true; |
| +} |
| + |
| bool HotwordService::IsServiceAvailable() { |
| error_message_ = 0; |
| @@ -371,3 +484,29 @@ void HotwordService::StopHotwordSession(HotwordClient* client) { |
| event_service->OnHotwordSessionStopped(); |
| #endif |
| } |
| + |
| +void HotwordService::SetPreviousLocalePref() { |
| + profile_->GetPrefs()->SetString(prefs::kHotwordPreviousLanguage, |
| + GetCurrentLocale(profile_)); |
| +} |
| + |
| +bool HotwordService::ShouldUninstallHotwordExtension() { |
| + std::string previous_locale = |
| + profile_->GetPrefs()->GetString(prefs::kHotwordPreviousLanguage); |
| + std::string locale = GetCurrentLocale(profile_); |
| + |
| + // If it's a new locale, then the old extension should be uninstalled. |
| + // If there is no previous locale pref, then this is the first install |
| + // so no need to uninstall first. |
| + return locale != previous_locale && |
| + profile_->GetPrefs()->HasPrefPath(prefs::kHotwordPreviousLanguage) && |
|
Yoyo Zhou
2014/06/18 00:33:21
nit: seems like the no-previous-locale check shoul
rpetterson
2014/06/18 02:08:44
Done.
|
| + HotwordService::DoesHotwordSupportLanguage(profile_); |
| +} |
| + |
| +void HotwordService::OnHotwordExtensionInstalled(bool success, |
|
Yoyo Zhou
2014/06/18 00:33:21
This callback doesn't really do anything. Is it ne
rpetterson
2014/06/18 02:08:44
I agree. Removed.
|
| + const std::string& error) { |
| + if (!success) |
| + LOG(WARNING) << "Cannot install extension with id " |
| + << extension_misc::kHotwordExtensionId |
| + << ": " << error; |
| +} |