blob: 43540eda2ce91a6181bd2e03020ae70fccd2b4b6 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/speech/extension_api/tts_engine_extension_observer.h"
#include "base/logging.h"
#include "base/memory/singleton.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/profiles/incognito_helpers.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/speech/extension_api/tts_engine_extension_api.h"
#include "chrome/browser/speech/tts_controller.h"
#include "chrome/common/extensions/api/speech/tts_engine_manifest_handler.h"
#include "components/keyed_service/content/browser_context_dependency_manager.h"
#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
#include "components/keyed_service/core/keyed_service.h"
#include "extensions/browser/event_router.h"
#include "extensions/browser/event_router_factory.h"
// Factory to load one instance of TtsExtensionLoaderChromeOs per profile.
class TtsEngineExtensionObserverFactory
: public BrowserContextKeyedServiceFactory {
public:
static TtsEngineExtensionObserver* GetForProfile(Profile* profile) {
return static_cast<TtsEngineExtensionObserver*>(
GetInstance()->GetServiceForBrowserContext(profile, true));
}
static TtsEngineExtensionObserverFactory* GetInstance() {
return base::Singleton<TtsEngineExtensionObserverFactory>::get();
}
private:
friend struct base::DefaultSingletonTraits<TtsEngineExtensionObserverFactory>;
TtsEngineExtensionObserverFactory()
: BrowserContextKeyedServiceFactory(
"TtsEngineExtensionObserver",
BrowserContextDependencyManager::GetInstance()) {
DependsOn(extensions::EventRouterFactory::GetInstance());
}
~TtsEngineExtensionObserverFactory() override {}
content::BrowserContext* GetBrowserContextToUse(
content::BrowserContext* context) const override {
// If given an incognito profile (including the Chrome OS login
// profile), share the service with the original profile.
return chrome::GetBrowserContextRedirectedInIncognito(context);
}
KeyedService* BuildServiceInstanceFor(
content::BrowserContext* profile) const override {
return new TtsEngineExtensionObserver(static_cast<Profile*>(profile));
}
};
TtsEngineExtensionObserver* TtsEngineExtensionObserver::GetInstance(
Profile* profile) {
return TtsEngineExtensionObserverFactory::GetInstance()->GetForProfile(
profile);
}
TtsEngineExtensionObserver::TtsEngineExtensionObserver(Profile* profile)
: extension_registry_observer_(this), profile_(profile) {
extension_registry_observer_.Add(
extensions::ExtensionRegistry::Get(profile_));
extensions::EventRouter* event_router =
extensions::EventRouter::Get(profile_);
DCHECK(event_router);
event_router->RegisterObserver(this, tts_engine_events::kOnSpeak);
event_router->RegisterObserver(this, tts_engine_events::kOnStop);
}
TtsEngineExtensionObserver::~TtsEngineExtensionObserver() {
}
bool TtsEngineExtensionObserver::SawExtensionLoad(
const std::string& extension_id,
bool update) {
bool previously_loaded =
engine_extension_ids_.find(extension_id) != engine_extension_ids_.end();
if (update)
engine_extension_ids_.insert(extension_id);
return previously_loaded;
}
const std::set<std::string> TtsEngineExtensionObserver::GetTtsExtensions() {
return engine_extension_ids_;
}
const std::vector<extensions::TtsVoice>*
TtsEngineExtensionObserver::GetRuntimeVoices(const std::string extension_id) {
auto it = extension_id_to_runtime_voices_.find(extension_id);
if (it == extension_id_to_runtime_voices_.end())
return nullptr;
return &it->second->voices;
}
void TtsEngineExtensionObserver::SetRuntimeVoices(
std::unique_ptr<extensions::TtsVoices> tts_voices,
const std::string extension_id) {
extension_id_to_runtime_voices_[extension_id] = std::move(tts_voices);
TtsController::GetInstance()->VoicesChanged();
}
void TtsEngineExtensionObserver::Shutdown() {
extensions::EventRouter::Get(profile_)->UnregisterObserver(this);
}
bool TtsEngineExtensionObserver::IsLoadedTtsEngine(
const std::string& extension_id) {
extensions::EventRouter* event_router =
extensions::EventRouter::Get(profile_);
DCHECK(event_router);
if (event_router->ExtensionHasEventListener(extension_id,
tts_engine_events::kOnSpeak) &&
event_router->ExtensionHasEventListener(extension_id,
tts_engine_events::kOnStop)) {
return true;
}
return false;
}
void TtsEngineExtensionObserver::OnListenerAdded(
const extensions::EventListenerInfo& details) {
if (!IsLoadedTtsEngine(details.extension_id))
return;
TtsController::GetInstance()->VoicesChanged();
engine_extension_ids_.insert(details.extension_id);
}
void TtsEngineExtensionObserver::OnExtensionUnloaded(
content::BrowserContext* browser_context,
const extensions::Extension* extension,
extensions::UnloadedExtensionReason reason) {
size_t erase_count = 0;
erase_count += engine_extension_ids_.erase(extension->id());
erase_count += extension_id_to_runtime_voices_.erase(extension->id());
if (erase_count > 0)
TtsController::GetInstance()->VoicesChanged();
}