blob: 480bf4cced4397f0d3bdb76b286add71ac7520ba [file] [log] [blame]
// Copyright (c) 2012 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/managed_mode.h"
#include "base/command_line.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog.h"
#include "chrome/browser/ui/app_modal_dialogs/javascript_app_modal_dialog.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/common/chrome_notification_types.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "content/public/browser/notification_service.h"
// static
ManagedMode* ManagedMode::GetInstance() {
return Singleton<ManagedMode>::get();
}
// static
void ManagedMode::RegisterPrefs(PrefService* prefs) {
prefs->RegisterBooleanPref(prefs::kInManagedMode, false);
// Set the value directly in the PrefService instead of using
// CommandLinePrefStore so we can change it at runtime.
if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kNoManaged))
GetInstance()->SetInManagedMode(false);
else if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kManaged))
GetInstance()->SetInManagedMode(true);
}
// static
bool ManagedMode::IsInManagedMode() {
return GetInstance()->IsInManagedModeImpl();
}
bool ManagedMode::IsInManagedModeImpl() {
// |g_browser_process| can be NULL during startup.
if (!g_browser_process)
return false;
// Local State can be NULL during unit tests.
if (!g_browser_process->local_state())
return false;
return g_browser_process->local_state()->GetBoolean(prefs::kInManagedMode);
}
// static
void ManagedMode::EnterManagedMode(Profile* profile,
const EnterCallback& callback) {
GetInstance()->EnterManagedModeImpl(profile, callback);
}
void ManagedMode::EnterManagedModeImpl(Profile* profile,
const EnterCallback& callback) {
if (IsInManagedModeImpl()) {
callback.Run(true);
return;
}
Profile* original_profile = profile->GetOriginalProfile();
if (!callbacks_.empty()) {
// We are already in the process of entering managed mode, waiting for
// browsers to close. Don't allow entering managed mode again for a
// different profile, and queue the callback for the same profile.
if (original_profile != managed_profile_)
callback.Run(false);
else
callbacks_.push_back(callback);
return;
}
if (!PlatformConfirmEnter()) {
callback.Run(false);
return;
}
managed_profile_ = original_profile;
// Close all other profiles.
// At this point, we shouldn't be waiting for other browsers to close (yet).
DCHECK_EQ(0u, browsers_to_close_.size());
for (BrowserList::const_iterator i = BrowserList::begin();
i != BrowserList::end(); ++i) {
if ((*i)->profile()->GetOriginalProfile() != managed_profile_)
browsers_to_close_.insert(*i);
}
if (browsers_to_close_.empty()) {
SetInManagedMode(true);
managed_profile_ = NULL;
callback.Run(true);
return;
}
callbacks_.push_back(callback);
registrar_.Add(this, content::NOTIFICATION_APP_EXITING,
content::NotificationService::AllSources());
registrar_.Add(this, chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED,
content::NotificationService::AllSources());
for (std::set<Browser*>::const_iterator i = browsers_to_close_.begin();
i != browsers_to_close_.end(); ++i) {
(*i)->window()->Close();
}
}
// static
void ManagedMode::LeaveManagedMode() {
GetInstance()->LeaveManagedModeImpl();
}
void ManagedMode::LeaveManagedModeImpl() {
bool confirmed = PlatformConfirmLeave();
if (confirmed)
SetInManagedMode(false);
}
void ManagedMode::OnBrowserAdded(Browser* browser) {
// Return early if we don't have any queued callbacks.
if (callbacks_.empty())
return;
if (browser->profile()->GetOriginalProfile() != managed_profile_)
FinalizeEnter(false);
}
void ManagedMode::OnBrowserRemoved(Browser* browser) {
// Return early if we don't have any queued callbacks.
if (callbacks_.empty())
return;
if (browser->profile()->GetOriginalProfile() == managed_profile_) {
// Ignore closing browser windows that are in managed mode.
return;
}
size_t count = browsers_to_close_.erase(browser);
DCHECK_EQ(1u, count);
if (browsers_to_close_.empty())
FinalizeEnter(true);
}
ManagedMode::ManagedMode() : managed_profile_(NULL) {
BrowserList::AddObserver(this);
}
ManagedMode::~ManagedMode() {
BrowserList::RemoveObserver(this);
DCHECK(!managed_profile_);
DCHECK_EQ(0u, callbacks_.size());
DCHECK_EQ(0u, browsers_to_close_.size());
}
void ManagedMode::Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
// Return early if we don't have any queued callbacks.
if (callbacks_.empty())
return;
switch (type) {
case content::NOTIFICATION_APP_EXITING: {
FinalizeEnter(false);
return;
}
case chrome::NOTIFICATION_BROWSER_CLOSE_CANCELLED: {
Browser* browser = content::Source<Browser>(source).ptr();
if (browsers_to_close_.find(browser) != browsers_to_close_.end())
FinalizeEnter(false);
return;
}
default: {
NOTREACHED();
break;
}
}
}
void ManagedMode::FinalizeEnter(bool result) {
if (result)
SetInManagedMode(true);
for (std::vector<EnterCallback>::iterator it = callbacks_.begin();
it != callbacks_.end(); ++it) {
it->Run(result);
}
managed_profile_ = NULL;
callbacks_.clear();
browsers_to_close_.clear();
registrar_.RemoveAll();
}
bool ManagedMode::PlatformConfirmEnter() {
// TODO(bauerb): Show platform-specific confirmation dialog.
return true;
}
bool ManagedMode::PlatformConfirmLeave() {
// TODO(bauerb): Show platform-specific confirmation dialog.
return true;
}
void ManagedMode::SetInManagedMode(bool in_managed_mode) {
g_browser_process->local_state()->SetBoolean(prefs::kInManagedMode,
in_managed_mode);
// This causes the avatar and the profile menu to get updated.
content::NotificationService::current()->Notify(
chrome::NOTIFICATION_PROFILE_CACHED_INFO_CHANGED,
content::NotificationService::AllBrowserContextsAndSources(),
content::NotificationService::NoDetails());
}