Commit e6ef7670 authored by Aga Wronska's avatar Aga Wronska Committed by Commit Bot

Invoke demo mode setup with 10 taps on OOBE welcome screen.

Bug: 857515
Test: DemoSetupTest
Change-Id: Iaa3106dacad12855c8c62bcff05bd91c2b6e0a1e
Reviewed-on: https://chromium-review.googlesource.com/1164253
Commit-Queue: Aga Wronska <agawronska@chromium.org>
Reviewed-by: default avatarJacob Dufault <jdufault@chromium.org>
Reviewed-by: default avatarMichael Giuffrida <michaelpg@chromium.org>
Cr-Commit-Position: refs/heads/master@{#583133}
parent a011e05f
...@@ -8,6 +8,8 @@ ...@@ -8,6 +8,8 @@
#include "base/files/scoped_temp_dir.h" #include "base/files/scoped_temp_dir.h"
#include "base/run_loop.h" #include "base/run_loop.h"
#include "base/strings/strcat.h" #include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h"
#include "base/time/time_to_iso8601.h"
#include "base/timer/timer.h" #include "base/timer/timer.h"
#include "base/values.h" #include "base/values.h"
#include "chrome/browser/chromeos/login/demo_mode/demo_setup_controller.h" #include "chrome/browser/chromeos/login/demo_mode/demo_setup_controller.h"
...@@ -240,6 +242,15 @@ class DemoSetupTest : public LoginManagerTest { ...@@ -240,6 +242,15 @@ class DemoSetupTest : public LoginManagerTest {
EXPECT_TRUE(JSExecute("cr.ui.Oobe.handleAccelerator('demo_mode');")); EXPECT_TRUE(JSExecute("cr.ui.Oobe.handleAccelerator('demo_mode');"));
} }
// Simulates multi-tap gesture that consists of |tapCount| clicks on the OOBE
// outer-container.
void MultiTapOobeContainer(int tapsCount) {
const std::string query = base::StrCat(
{"for (var i = 0; i < ", base::NumberToString(tapsCount), "; ++i)",
"{ document.querySelector('#outer-container').click(); }"});
EXPECT_TRUE(JSExecute(query));
}
void ClickOkOnConfirmationDialog() { void ClickOkOnConfirmationDialog() {
EXPECT_TRUE(JSExecute("document.querySelector('.cr-dialog-ok').click();")); EXPECT_TRUE(JSExecute("document.querySelector('.cr-dialog-ok').click();"));
} }
...@@ -415,12 +426,6 @@ class DemoSetupTest : public LoginManagerTest { ...@@ -415,12 +426,6 @@ class DemoSetupTest : public LoginManagerTest {
base::RunLoop().RunUntilIdle(); base::RunLoop().RunUntilIdle();
} }
private:
void DisableConfirmationDialogAnimations() {
EXPECT_TRUE(
JSExecute("cr.ui.dialogs.BaseDialog.ANIMATE_STABLE_DURATION = 0;"));
}
bool JSExecute(const std::string& script) { bool JSExecute(const std::string& script) {
return content::ExecuteScript(web_contents(), script); return content::ExecuteScript(web_contents(), script);
} }
...@@ -429,6 +434,21 @@ class DemoSetupTest : public LoginManagerTest { ...@@ -429,6 +434,21 @@ class DemoSetupTest : public LoginManagerTest {
content::ExecuteScriptAsync(web_contents(), script); content::ExecuteScriptAsync(web_contents(), script);
} }
// Sets fake time in MultiTapDetector to remove dependency on real time in
// test environment.
void SetFakeTimeForMultiTapDetector(base::Time fake_time) {
const std::string query =
base::StrCat({"MultiTapDetector.FAKE_TIME_FOR_TESTS = new Date('",
base::TimeToISO8601(fake_time), "');"});
EXPECT_TRUE(JSExecute(query));
}
private:
void DisableConfirmationDialogAnimations() {
EXPECT_TRUE(
JSExecute("cr.ui.dialogs.BaseDialog.ANIMATE_STABLE_DURATION = 0;"));
}
// TODO(agawronska): Maybe create a separate test fixture for offline setup. // TODO(agawronska): Maybe create a separate test fixture for offline setup.
base::ScopedTempDir fake_policy_dir_; base::ScopedTempDir fake_policy_dir_;
policy::MockCloudPolicyStore mock_policy_store_; policy::MockCloudPolicyStore mock_policy_store_;
...@@ -460,6 +480,33 @@ IN_PROC_BROWSER_TEST_F(DemoSetupTest, ShowConfirmationDialogAndCancel) { ...@@ -460,6 +480,33 @@ IN_PROC_BROWSER_TEST_F(DemoSetupTest, ShowConfirmationDialogAndCancel) {
EXPECT_FALSE(IsScreenShown(OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES)); EXPECT_FALSE(IsScreenShown(OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES));
} }
IN_PROC_BROWSER_TEST_F(DemoSetupTest, InvokeWithTaps) {
// Use fake time to avoid flakiness.
SetFakeTimeForMultiTapDetector(base::Time::UnixEpoch());
EXPECT_FALSE(IsConfirmationDialogShown());
MultiTapOobeContainer(10);
EXPECT_TRUE(IsConfirmationDialogShown());
}
IN_PROC_BROWSER_TEST_F(DemoSetupTest, DoNotInvokeWithNonConsecutiveTaps) {
// Use fake time to avoid flakiness.
const base::Time kFakeTime = base::Time::UnixEpoch();
SetFakeTimeForMultiTapDetector(kFakeTime);
EXPECT_FALSE(IsConfirmationDialogShown());
MultiTapOobeContainer(5);
EXPECT_FALSE(IsConfirmationDialogShown());
// Advance time to make interval in between taps longer than expected by
// multi-tap gesture detector.
SetFakeTimeForMultiTapDetector(kFakeTime +
base::TimeDelta::FromMilliseconds(500));
MultiTapOobeContainer(5);
EXPECT_FALSE(IsConfirmationDialogShown());
}
IN_PROC_BROWSER_TEST_F(DemoSetupTest, OnlineSetupFlowSuccess) { IN_PROC_BROWSER_TEST_F(DemoSetupTest, OnlineSetupFlowSuccess) {
// Simulate successful online setup. // Simulate successful online setup.
EnterpriseEnrollmentHelper::SetupEnrollmentHelperMock( EnterpriseEnrollmentHelper::SetupEnrollmentHelperMock(
......
...@@ -178,14 +178,8 @@ WebUILoginView::WebUILoginView(const WebViewSettings& settings) ...@@ -178,14 +178,8 @@ WebUILoginView::WebUILoginView(const WebViewSettings& settings)
ui::VKEY_S, ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN | ui::EF_SHIFT_DOWN)] = ui::VKEY_S, ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN | ui::EF_SHIFT_DOWN)] =
kAccelNameBootstrappingSlave; kAccelNameBootstrappingSlave;
const bool is_demo_mode_enabled = accel_map_[ui::Accelerator(
base::CommandLine::ForCurrentProcess()->HasSwitch( ui::VKEY_D, ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN)] = kAccelNameDemoMode;
chromeos::switches::kEnableDemoMode);
if (is_demo_mode_enabled) {
accel_map_[ui::Accelerator(ui::VKEY_D,
ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN)] =
kAccelNameDemoMode;
}
accel_map_[ui::Accelerator(ui::VKEY_I, ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN)] = accel_map_[ui::Accelerator(ui::VKEY_I, ui::EF_SHIFT_DOWN | ui::EF_ALT_DOWN)] =
kAccelSendFeedback; kAccelSendFeedback;
......
// Copyright 2018 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.
/**
* @fileoverview Multi-tap gesture detector for web UI OOBE.
*/
/** Multi-tap gesture detector. */
class MultiTapDetector {
/**
* @param {!Element} element UI element to attach the multi-tap detector to.
* @param {number} tapsCount Number of taps in multi-tap gesture to detect.
* @param {!function()} callback Callback to be called when multi-tap gesture
* is detected.
*/
constructor(element, tapsCount, callback) {
assert(callback);
assert(tapsCount > 0);
assert(element);
/** @private {number} */
this.tapsSeen_ = 0;
/** @private {?Date} */
this.lastTapTime_ = null;
this.callback_ = callback;
this.tapsCount_ = tapsCount;
element.addEventListener('click', this.onTap_.bind(this));
}
/**
* Returns current time or fake time for testing if set.
* @return {!Date}
* @private
*/
getCurrentTime_() {
return MultiTapDetector.FAKE_TIME_FOR_TESTS ?
MultiTapDetector.FAKE_TIME_FOR_TESTS :
new Date();
}
/**
* Handles tap event.
* @private
*/
onTap_() {
let timestamp = this.getCurrentTime_();
if (!this.lastTapTime_ ||
timestamp - this.lastTapTime_ <
MultiTapDetector.IN_BETWEEN_TAPS_TIME_MS) {
this.tapsSeen_++;
if (this.tapsSeen_ >= this.tapsCount_) {
this.tapsSeen_ = 0;
this.callback_();
}
} else {
this.tapsSeen_ = 0;
}
this.lastTapTime_ = timestamp;
}
}
/**
* Time in between taps used to recognize multi-tap gesture.
* @const {number}
*/
MultiTapDetector.IN_BETWEEN_TAPS_TIME_MS = 400;
/**
* Fake time used for testing. If set it will be used instead of the current
* time.
* @const {?Date}
*/
MultiTapDetector.FAKE_TIME_FOR_TESTS = null;
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
// <include src="oobe_screen_network.js"> // <include src="oobe_screen_network.js">
// <include src="oobe_screen_update.js"> // <include src="oobe_screen_update.js">
// <include src="oobe_screen_welcome.js"> // <include src="oobe_screen_welcome.js">
// <include src="multi_tap_detector.js">
cr.define('cr.ui.Oobe', function() { cr.define('cr.ui.Oobe', function() {
return { return {
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "ash/public/interfaces/event_rewriter_controller.mojom.h" #include "ash/public/interfaces/event_rewriter_controller.mojom.h"
#include "ash/shell.h" #include "ash/shell.h"
#include "base/bind.h" #include "base/bind.h"
#include "base/command_line.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "base/values.h" #include "base/values.h"
#include "chrome/browser/browser_process.h" #include "chrome/browser/browser_process.h"
...@@ -179,6 +180,9 @@ void CoreOobeHandler::Initialize() { ...@@ -179,6 +180,9 @@ void CoreOobeHandler::Initialize() {
void CoreOobeHandler::GetAdditionalParameters(base::DictionaryValue* dict) { void CoreOobeHandler::GetAdditionalParameters(base::DictionaryValue* dict) {
dict->SetKey("isInTabletMode", dict->SetKey("isInTabletMode",
base::Value(TabletModeClient::Get()->tablet_mode_enabled())); base::Value(TabletModeClient::Get()->tablet_mode_enabled()));
bool is_demo_mode_enabled = base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableDemoMode);
dict->SetKey("isDemoModeEnabled", base::Value(is_demo_mode_enabled));
} }
void CoreOobeHandler::RegisterMessages() { void CoreOobeHandler::RegisterMessages() {
......
...@@ -274,6 +274,13 @@ cr.define('cr.ui.login', function() { ...@@ -274,6 +274,13 @@ cr.define('cr.ui.login', function() {
*/ */
oobe_configuration_: {}, oobe_configuration_: {},
/**
* Detects multi-tap gesture that invokes demo mode setup in OOBE.
* @type {?MultiTapDetector}
* @private
*/
demoModeStartListener_: null,
/** /**
* Error message (bubble) was shown. This is checked in tests. * Error message (bubble) was shown. This is checked in tests.
*/ */
...@@ -495,10 +502,7 @@ cr.define('cr.ui.login', function() { ...@@ -495,10 +502,7 @@ cr.define('cr.ui.login', function() {
} else if (name == ACCELERATOR_BOOTSTRAPPING_SLAVE) { } else if (name == ACCELERATOR_BOOTSTRAPPING_SLAVE) {
chrome.send('setOobeBootstrappingSlave'); chrome.send('setOobeBootstrappingSlave');
} else if (name == ACCELERATOR_DEMO_MODE) { } else if (name == ACCELERATOR_DEMO_MODE) {
if (DEMO_MODE_SETUP_AVAILABLE_SCREEN_GROUP.indexOf(currentStepId) !=
-1) {
this.showEnableDemoModeDialog_(); this.showEnableDemoModeDialog_();
}
} else if (name == ACCELERATOR_SEND_FEEDBACK) { } else if (name == ACCELERATOR_SEND_FEEDBACK) {
chrome.send('sendFeedback'); chrome.send('sendFeedback');
} }
...@@ -896,6 +900,14 @@ cr.define('cr.ui.login', function() { ...@@ -896,6 +900,14 @@ cr.define('cr.ui.login', function() {
} }
}, },
/** Initializes demo mode start listener. */
initializeDemoModeMultiTapListener: function() {
if (this.displayType_ == DISPLAY_TYPE.OOBE) {
this.demoModeStartListener_ = new MultiTapDetector(
$('outer-container'), 10, this.showEnableDemoModeDialog_.bind(this));
}
},
/** /**
* Prepares screens to use in login display. * Prepares screens to use in login display.
*/ */
...@@ -991,7 +1003,17 @@ cr.define('cr.ui.login', function() { ...@@ -991,7 +1003,17 @@ cr.define('cr.ui.login', function() {
* Shows the enable demo mode dialog. * Shows the enable demo mode dialog.
* @private * @private
*/ */
showEnableDemoModeDialog_: function(promptText, requisition) { showEnableDemoModeDialog_: function() {
var isDemoModeEnabled = loadTimeData.getBoolean('isDemoModeEnabled');
if (!isDemoModeEnabled) {
console.warn('Cannot setup demo mode, because it is disabled.');
return;
}
var currentStepId = this.screens_[this.currentStep_];
if (!DEMO_MODE_SETUP_AVAILABLE_SCREEN_GROUP.includes(currentStepId))
return;
if (!this.enableDemoModeDialog_) { if (!this.enableDemoModeDialog_) {
this.enableDemoModeDialog_ = this.enableDemoModeDialog_ =
new cr.ui.dialogs.ConfirmDialog(document.body); new cr.ui.dialogs.ConfirmDialog(document.body);
...@@ -1000,12 +1022,13 @@ cr.define('cr.ui.login', function() { ...@@ -1000,12 +1022,13 @@ cr.define('cr.ui.login', function() {
this.enableDemoModeDialog_.setCancelLabel( this.enableDemoModeDialog_.setCancelLabel(
loadTimeData.getString('enableDemoModeDialogCancel')); loadTimeData.getString('enableDemoModeDialogCancel'));
} }
this.enableDemoModeDialog_.showWithTitle( this.enableDemoModeDialog_.showWithTitle(
loadTimeData.getString('enableDemoModeDialogTitle'), loadTimeData.getString('enableDemoModeDialogTitle'),
loadTimeData.getString('enableDemoModeDialogText'), loadTimeData.getString('enableDemoModeDialogText'),
function() { // onOk function() { // onOk
chrome.send('setupDemoMode'); chrome.send('setupDemoMode');
}, ); });
}, },
/** /**
...@@ -1053,6 +1076,7 @@ cr.define('cr.ui.login', function() { ...@@ -1053,6 +1076,7 @@ cr.define('cr.ui.login', function() {
} }
instance.initializeOOBEScreens(); instance.initializeOOBEScreens();
instance.initializeDemoModeMultiTapListener();
window.addEventListener('resize', instance.onWindowResize_.bind(instance)); window.addEventListener('resize', instance.onWindowResize_.bind(instance));
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment