blob: 4d1c0b366ec621516603efef206a33aef34835ec [file] [log] [blame]
// Copyright 2015 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/chromeos/first_run/goodies_displayer.h"
#include "base/command_line.h"
#include "base/location.h"
#include "base/single_thread_task_runner.h"
#include "base/task_scheduler/post_task.h"
#include "base/threading/thread_task_runner_handle.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/login/startup_utils.h"
#include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/browser_tabstrip.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "components/prefs/pref_service.h"
#include "components/user_manager/user.h"
#include "components/user_manager/user_manager.h"
#include "content/public/browser/browser_thread.h"
namespace chromeos {
namespace first_run {
namespace {
GoodiesDisplayer* g_goodies_displayer = nullptr;
GoodiesDisplayerTestInfo* g_test_info = nullptr;
// Checks timestamp on OOBE Complete flag file, or use fake device age for test.
// kCanShowOobeGoodiesPage defaults to |true|; set to |false| (return |false|)
// for any device over kMaxDaysAfterOobeForGoodies days old, to avoid showing
// Goodies after update on older devices.
bool CheckGoodiesPrefAgainstOobeTimestamp() {
const int days_since_oobe =
g_test_info ? g_test_info->days_since_oobe
: StartupUtils::GetTimeSinceOobeFlagFileCreation().InDays();
return days_since_oobe <= GoodiesDisplayer::kMaxDaysAfterOobeForGoodies;
}
// Callback into main thread to set pref to |false| if too long since oobe, or
// to create GoodiesDisplayer otherwise.
void UpdateGoodiesPrefCantShow(bool can_show_goodies) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (can_show_goodies) {
if (!g_goodies_displayer)
g_goodies_displayer = new GoodiesDisplayer();
} else {
g_browser_process->local_state()->SetBoolean(prefs::kCanShowOobeGoodiesPage,
false);
}
if (g_test_info) {
g_test_info->setup_complete = true;
if (!g_test_info->on_setup_complete_callback.is_null())
g_test_info->on_setup_complete_callback.Run();
}
}
} // namespace
const char GoodiesDisplayer::kGoodiesURL[] =
"https://www.google.com/chrome/devices/goodies.html";
GoodiesDisplayer::GoodiesDisplayer() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
BrowserList::AddObserver(this);
}
GoodiesDisplayer::~GoodiesDisplayer() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
BrowserList::RemoveObserver(this);
}
// If Goodies page hasn't been shown yet, and Chromebook isn't too old, create
// GoodiesDisplayer to observe BrowserList. Return |true| if checking age.
// static
bool GoodiesDisplayer::Init() {
const bool can_show = g_browser_process->local_state()->GetBoolean(
prefs::kCanShowOobeGoodiesPage);
if (can_show) {
base::PostTaskWithTraitsAndReplyWithResult(
FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT},
base::Bind(&CheckGoodiesPrefAgainstOobeTimestamp),
base::Bind(&UpdateGoodiesPrefCantShow));
}
return can_show;
}
// static
void GoodiesDisplayer::InitForTesting(GoodiesDisplayerTestInfo* test_info) {
CHECK(!g_test_info) << "GoodiesDisplayer::InitForTesting called twice";
g_test_info = test_info;
test_info->setup_complete = !Init();
}
// static
void GoodiesDisplayer::Delete() {
delete g_goodies_displayer;
g_goodies_displayer = nullptr;
}
// If conditions enumerated below are met, this loads the Oobe Goodies page for
// new Chromebooks; when appropriate, it uses pref to mark page as shown,
// removes itself from BrowserListObservers, and deletes itself.
void GoodiesDisplayer::OnBrowserSetLastActive(Browser* browser) {
// 1. Must be an actual tabbed browser window.
if (browser->type() != Browser::TYPE_TABBED)
return;
// 2. Not guest or incognito session or supervised user (keep observing).
user_manager::User* user = user_manager::UserManager::Get()->GetActiveUser();
if (browser->profile()->IsOffTheRecord() || (user && user->IsSupervised()))
return;
PrefService* local_state = g_browser_process->local_state();
// 3. Not previously shown, or otherwise marked as unavailable.
if (local_state->GetBoolean(prefs::kCanShowOobeGoodiesPage)) {
// 4. Device not enterprise enrolled.
const bool enterprise_managed = g_browser_process->platform_part()
->browser_policy_connector_chromeos()
->IsEnterpriseManaged();
// 5. --no-first-run not specified, as it is for tests. --force-run takes
// precedence over --no-first-run.
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
const bool first_run_permitted =
command_line->HasSwitch(switches::kForceFirstRun) ||
!command_line->HasSwitch(switches::kNoFirstRun);
if (!enterprise_managed && first_run_permitted)
chrome::AddTabAt(browser, GURL(kGoodiesURL), 2, false);
// Set to |false| whether enterprise enrolled or Goodies shown.
local_state->SetBoolean(prefs::kCanShowOobeGoodiesPage, false);
}
// Regardless of how we got here, we don't henceforth need to show Goodies.
base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, base::Bind(&Delete));
}
GoodiesDisplayerTestInfo::GoodiesDisplayerTestInfo()
: days_since_oobe(0), setup_complete(false) {}
GoodiesDisplayerTestInfo::~GoodiesDisplayerTestInfo() {}
} // namespace first_run
} // namespace chromeos