Commit c3b66273 authored by khmel's avatar khmel Committed by Commit bot

arc: Provide progress to load TOS content for OptIn.

This implements progress for loading TOS content for OptIn
workflow with error/retry support. Also fixes few UI bugs
in OptIn layout windows.

BUG=b/29419423
TEST=Manually on device. Emulate error conditions on different
     stages of OptIn workflow. OptIn is correctly recoverable
     in each case.
CQ_INCLUDE_TRYBOTS=tryserver.chromium.linux:closure_compilation

Review-Url: https://codereview.chromium.org/2137713002
Cr-Commit-Position: refs/heads/master@{#404550}
parent d745e789
...@@ -667,7 +667,7 @@ void ArcAuthService::StartUI() { ...@@ -667,7 +667,7 @@ void ArcAuthService::StartUI() {
if (initial_opt_in_) { if (initial_opt_in_) {
initial_opt_in_ = false; initial_opt_in_ = false;
ShowUI(UIPage::START, base::string16()); ShowUI(UIPage::TERMS_PROGRESS, base::string16());
} else { } else {
context_->PrepareContext(); context_->PrepareContext();
} }
......
...@@ -57,7 +57,8 @@ class ArcAuthService : public ArcService, ...@@ -57,7 +57,8 @@ class ArcAuthService : public ArcService,
enum class UIPage { enum class UIPage {
NO_PAGE, // Hide everything. NO_PAGE, // Hide everything.
START, // Initial start page. TERMS_PROGRESS, // Terms loading progress page.
TERMS, // Terms content page.
LSO_PROGRESS, // LSO loading progress page. LSO_PROGRESS, // LSO loading progress page.
LSO, // LSO page to enter user's credentials. LSO, // LSO page to enter user's credentials.
START_PROGRESS, // Arc starting progress page. START_PROGRESS, // Arc starting progress page.
......
...@@ -138,6 +138,9 @@ void ArcSupportHost::Initialize() { ...@@ -138,6 +138,9 @@ void ArcSupportHost::Initialize() {
loadtime_data->SetString( loadtime_data->SetString(
"textBackupRestore", "textBackupRestore",
l10n_util::GetStringUTF16(IDS_ARC_OPT_IN_DIALOG_BACKUP_RESTORE)); l10n_util::GetStringUTF16(IDS_ARC_OPT_IN_DIALOG_BACKUP_RESTORE));
loadtime_data->SetString(
"serverError",
l10n_util::GetStringUTF16(IDS_ARC_SERVER_COMMUNICATION_ERROR));
const std::string& app_locale = g_browser_process->GetApplicationLocale(); const std::string& app_locale = g_browser_process->GetApplicationLocale();
const std::string& country_code = base::CountryCodeForCurrentTimezone(); const std::string& country_code = base::CountryCodeForCurrentTimezone();
......
...@@ -8,7 +8,8 @@ ...@@ -8,7 +8,8 @@
* @type {Array<string>} * @type {Array<string>}
*/ */
var UI_PAGES = ['none', var UI_PAGES = ['none',
'start', 'terms-loading',
'terms',
'lso-loading', 'lso-loading',
'lso', 'lso',
'arc-loading', 'arc-loading',
...@@ -58,6 +59,12 @@ var termsReloadTimeout = null; ...@@ -58,6 +59,12 @@ var termsReloadTimeout = null;
*/ */
var currentDeviceId = null; var currentDeviceId = null;
/**
* Indicates that terms were accepted by user.
* @type {boolean}
*/
var termsAccepted = false;
/** /**
* Closes current window in response to request from native code. This does not * Closes current window in response to request from native code. This does not
* issue 'cancelAuthCode' message to native code. * issue 'cancelAuthCode' message to native code.
...@@ -105,9 +112,6 @@ function initialize(data, deviceId) { ...@@ -105,9 +112,6 @@ function initialize(data, deviceId) {
js: { files: ['playstore.js'] }, js: { files: ['playstore.js'] },
run_at: 'document_end' run_at: 'document_end'
}]); }]);
// Applying localization changes page layout, update terms height.
updateTermsHeight();
} }
/** /**
...@@ -171,6 +175,9 @@ function updateTermsHeight() { ...@@ -171,6 +175,9 @@ function updateTermsHeight() {
var setTermsHeight = function() { var setTermsHeight = function() {
var doc = appWindow.contentWindow.document; var doc = appWindow.contentWindow.document;
var termsContainer = doc.getElementById('terms-container'); var termsContainer = doc.getElementById('terms-container');
// Reset terms-view height in order to stabilize style computation. For
// some reason, child webview affects final result.
termsView.style.height = '0px';
var style = window.getComputedStyle(termsContainer, null); var style = window.getComputedStyle(termsContainer, null);
var height = style.getPropertyValue('height'); var height = style.getPropertyValue('height');
termsView.style.height = height; termsView.style.height = height;
...@@ -277,10 +284,17 @@ function showPageWithStatus(pageId, status) { ...@@ -277,10 +284,17 @@ function showPageWithStatus(pageId, status) {
return; return;
} }
if (UI_PAGES[pageId] == 'start') { if (UI_PAGES[pageId] == 'terms-loading') {
termsAccepted = false;
loadInitialTerms(); loadInitialTerms();
} else if (UI_PAGES[pageId] == 'error' || } else {
UI_PAGES[pageId] == 'error-with-feedback') { // Explicit request to start not from start page. Assume terms are
// accepted in this case.
termsAccepted = true;
}
if (UI_PAGES[pageId] == 'error' ||
UI_PAGES[pageId] == 'error-with-feedback') {
setErrorMessage(status); setErrorMessage(status);
} }
showPage(UI_PAGES[pageId]); showPage(UI_PAGES[pageId]);
...@@ -297,25 +311,32 @@ chrome.app.runtime.onLaunched.addListener(function() { ...@@ -297,25 +311,32 @@ chrome.app.runtime.onLaunched.addListener(function() {
var onAppContentLoad = function() { var onAppContentLoad = function() {
var doc = appWindow.contentWindow.document; var doc = appWindow.contentWindow.document;
lsoView = doc.getElementById('arc-support'); lsoView = doc.getElementById('arc-support');
// Apply absolute dimension to webview tag in order to avoid UI glitch
// when embedded content layout is visible for user, even if 100% width and
// height are set in css file.
// TODO(khmel): Investigate why relative layout is not enough.
lsoView.style.width = appWindow.innerBounds.width + 'px';
lsoView.style.height = appWindow.innerBounds.height + 'px';
var isApprovalResponse = function(url) { var isApprovalResponse = function(url) {
var resultUrlPrefix = 'https://accounts.google.com/o/oauth2/approval?'; var resultUrlPrefix = 'https://accounts.google.com/o/oauth2/approval?';
return url.substring(0, resultUrlPrefix.length) == resultUrlPrefix; return url.substring(0, resultUrlPrefix.length) == resultUrlPrefix;
}; };
var lsoError = false;
var onLsoViewRequestResponseStarted = function(details) { var onLsoViewRequestResponseStarted = function(details) {
if (isApprovalResponse(details.url)) { if (isApprovalResponse(details.url)) {
showPage('arc-loading'); showPage('arc-loading');
} }
lsoError = false;
};
var onLsoViewErrorOccurred = function(details) {
setErrorMessage(appWindow.contentWindow.loadTimeData.getString(
'serverError'));
showPage('error');
lsoError = true;
}; };
var onLsoViewContentLoad = function() { var onLsoViewContentLoad = function() {
if (lsoError) {
return;
}
if (!isApprovalResponse(lsoView.src)) { if (!isApprovalResponse(lsoView.src)) {
// Show LSO page when its content is ready. // Show LSO page when its content is ready.
showPage('lso'); showPage('lso');
...@@ -324,8 +345,8 @@ chrome.app.runtime.onLaunched.addListener(function() { ...@@ -324,8 +345,8 @@ chrome.app.runtime.onLaunched.addListener(function() {
lsoView.executeScript({code: 'document.title;'}, function(results) { lsoView.executeScript({code: 'document.title;'}, function(results) {
var authCodePrefix = 'Success code='; var authCodePrefix = 'Success code=';
if (results[0].substring(0, authCodePrefix.length) == if (results && results.length == 1 && typeof results[0] == 'string' &&
authCodePrefix) { results[0].substring(0, authCodePrefix.length) == authCodePrefix) {
var authCode = results[0].substring(authCodePrefix.length); var authCode = results[0].substring(authCodePrefix.length);
sendNativeMessage('setAuthCode', {code: authCode}); sendNativeMessage('setAuthCode', {code: authCode});
} else { } else {
...@@ -343,31 +364,40 @@ chrome.app.runtime.onLaunched.addListener(function() { ...@@ -343,31 +364,40 @@ chrome.app.runtime.onLaunched.addListener(function() {
lsoView.request.onResponseStarted.addListener( lsoView.request.onResponseStarted.addListener(
onLsoViewRequestResponseStarted, requestFilter); onLsoViewRequestResponseStarted, requestFilter);
lsoView.request.onErrorOccurred.addListener(
onLsoViewErrorOccurred, requestFilter);
lsoView.addEventListener('contentload', onLsoViewContentLoad); lsoView.addEventListener('contentload', onLsoViewContentLoad);
termsView = doc.getElementById('terms'); termsView = doc.getElementById('terms-view');
// Handle terms view completed event. Enable button 'Agree' in case terms var termsError = false;
// were loaded successfully and try to reload its content on error. var onTermsViewBeforeRequest = function(details) {
var termsReloadRetryTimeMs = 1000; // 1 second showPage('terms-loading');
function onTermsViewRequestCompleted(details) { termsError = false;
if (termsReloadTimeout) { };
clearTimeout(termsReloadTimeout);
termsReloadTimeout = null; var onTermsViewErrorOccurred = function(details) {
} termsAccepted = false;
if (details.statusCode == 200) { setErrorMessage(appWindow.contentWindow.loadTimeData.getString(
doc.getElementById('button-agree').disabled = false; 'serverError'));
} else { showPage('error');
termsReloadTimeout = setTimeout(loadInitialTerms, termsError = true;
termsReloadRetryTimeMs); };
termsReloadRetryTimeMs = termsReloadRetryTimeMs * 2;
if (termsReloadRetryTimeMs > 30000) { var onTermsViewContentLoad = function() {
termsReloadRetryTimeMs = 30000; if (termsError) {
} return;
} }
} showPage('terms');
termsView.request.onCompleted.addListener(onTermsViewRequestCompleted, updateTermsHeight();
requestFilter); };
termsView.request.onBeforeRequest.addListener(onTermsViewBeforeRequest,
requestFilter);
termsView.request.onErrorOccurred.addListener(onTermsViewErrorOccurred,
requestFilter);
termsView.addEventListener('contentload', onTermsViewContentLoad);
// webview is not allowed to open links in the new window. Hook these events // webview is not allowed to open links in the new window. Hook these events
// and open links in context of main page. // and open links in context of main page.
...@@ -377,6 +407,8 @@ chrome.app.runtime.onLaunched.addListener(function() { ...@@ -377,6 +407,8 @@ chrome.app.runtime.onLaunched.addListener(function() {
}); });
var onAgree = function() { var onAgree = function() {
termsAccepted = true;
var enableMetrics = doc.getElementById('enable-metrics'); var enableMetrics = doc.getElementById('enable-metrics');
if (!enableMetrics.hidden) { if (!enableMetrics.hidden) {
sendNativeMessage('enableMetrics', { sendNativeMessage('enableMetrics', {
...@@ -401,7 +433,11 @@ chrome.app.runtime.onLaunched.addListener(function() { ...@@ -401,7 +433,11 @@ chrome.app.runtime.onLaunched.addListener(function() {
}; };
var onRetry = function() { var onRetry = function() {
sendNativeMessage('startLso'); if (termsAccepted) {
sendNativeMessage('startLso');
} else {
loadInitialTerms();
}
}; };
var onSendFeedback = function() { var onSendFeedback = function() {
......
...@@ -16,7 +16,11 @@ webview, ...@@ -16,7 +16,11 @@ webview,
} }
#arc-support { #arc-support {
padding: 0; width: 960px;
}
#terms-view {
width: 468px;
} }
.button-separator { .button-separator {
...@@ -55,7 +59,7 @@ webview, ...@@ -55,7 +59,7 @@ webview,
.section-checkbox-container { .section-checkbox-container {
margin: auto; margin: auto;
padding: 16px 0 0 0; padding: 8px 0 0 0;
text-align: left; text-align: left;
width: 468px; width: 468px;
} }
...@@ -64,7 +68,7 @@ webview, ...@@ -64,7 +68,7 @@ webview,
border: 1px solid #e6e6e6; border: 1px solid #e6e6e6;
color: rgba(0, 0, 0, 0.54); color: rgba(0, 0, 0, 0.54);
flex: auto; flex: auto;
margin: auto; margin: 0 auto 8px auto;
overflow: hidden; overflow: hidden;
padding: 0; padding: 0;
width: 468px; width: 468px;
......
...@@ -42,13 +42,19 @@ ...@@ -42,13 +42,19 @@
<script src="chrome://resources/js/i18n_template_no_process.js"></script> <script src="chrome://resources/js/i18n_template_no_process.js"></script>
</head> </head>
<body> <body>
<div id="start" class="section section-flex"> <div id="terms-loading" class="section">
<img class="image-header" src="images/header.png">
<p class="text-title" i18n-content="greetingHeader"></p>
<p class="text-desc" i18n-content="greetingDescription"></p>
<paper-progress class="blue" indeterminate></paper-progress>
</div>
<div id="terms" class="section section-flex" hidden>
<img class="image-header" src="images/header.png"> <img class="image-header" src="images/header.png">
<p class="text-title" i18n-content="greetingHeader"></p> <p class="text-title" i18n-content="greetingHeader"></p>
<p class="text-desc" i18n-content="greetingDescription"></p> <p class="text-desc" i18n-content="greetingDescription"></p>
<p class="text-terms-title" i18n-content="termsOfService"></p> <p class="text-terms-title" i18n-content="termsOfService"></p>
<div class="section-terms" id ="terms-container"> <div class="section-terms" id ="terms-container">
<webview id="terms" partition="persist:arc_support"></webview> <webview id="terms-view" partition="persist:arc_support"></webview>
</div> </div>
<div class="layout horizontal section-checkbox-container"> <div class="layout horizontal section-checkbox-container">
<input type="checkbox" class="checkbox-option" id="enable-metrics" hidden> <input type="checkbox" class="checkbox-option" id="enable-metrics" hidden>
...@@ -64,8 +70,7 @@ ...@@ -64,8 +70,7 @@
i18n-content="buttonCancel"> i18n-content="buttonCancel">
</paper-button> </paper-button>
<div class="button-separator"></div> <div class="button-separator"></div>
<paper-button class="blue" id="button-agree" i18n-content="buttonAgree" <paper-button class="blue" id="button-agree" i18n-content="buttonAgree">
disabled>
</paper-button> </paper-button>
</div> </div>
</div> </div>
......
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