0

[CrOS Cellular] Add carrier provisioning page.

This CL loads the carrier page and handles any errors which may occur
while interacting with it. Note that this CL makes use of a <webview>,
so it modifies two JSON files to provide permission to
chrome://cellular-setup to use that element.

Bug: 991826
Change-Id: I6a3872dc5544ca387c01b9b4cb97bd7d1f4e9bb5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1767601
Reviewed-by: Devlin <rdevlin.cronin@chromium.org>
Reviewed-by: Steven Bennetts <stevenjb@chromium.org>
Commit-Queue: Kyle Horimoto <khorimoto@chromium.org>
Cr-Commit-Position: refs/heads/master@{#691855}
This commit is contained in:
Kyle Horimoto
2019-08-29 23:31:12 +00:00
committed by Commit Bot
parent 4bf79f2d2e
commit cfec9d675d
9 changed files with 285 additions and 16 deletions
chrome
app
browser
common
extensions
extensions/common/api
ui/webui/resources/cr_components/chromeos/cellular_setup

@ -222,8 +222,17 @@
<message name="IDS_CELLULAR_SETUP_SIM_DETECT_PAGE_ERROR_MESSAGE" desc="Message displayed under title in cellular setup when Chrome OS encounters an error preparing the cellular device for setup. Prompts user to insert SIM and try again.">
Please insert your SIM and try again
</message>
<message name="IDS_CELLULAR_SETUP_PROVISIONING_PAGE_TITLE" desc="Title for cellular setup step in which the user uses the embedded carrier provisioning portal to make payment and activate the device." translateable="false">
Provisioning Page
<message name="IDS_CELLULAR_SETUP_PROVISIONING_PAGE_LOADING_TITLE" desc="Title for cellular setup step which indicates that a connection is in progress to the user's mobile data provider (e.g., Verizon).">
Connecting to <ph name="CARRIER_NAME">$1<ex>Google Fi</ex></ph>
</message>
<message name="IDS_CELLULAR_SETUP_PROVISIONING_PAGE_ERROR_TITLE" desc="Title for cellular setup step which indicates that the Chromebook was unable to establish a connection to the user's mobile data provider (e.g., Verizon).">
Couldn't connect to <ph name="CARRIER_NAME">$1<ex>Google Fi</ex></ph>
</message>
<message name="IDS_CELLULAR_SETUP_PROVISIONING_PAGE_ERROR_MESSAGE" desc="Message for the cellular setup step which indicates that the Chromebook was unable to establish a connection to the user's mobile data provider (e.g., Verizon).">
Please try again. For technical support, contact <ph name="CARRIER_NAME">$1<ex>Google Fi</ex></ph>.
</message>
<message name="IDS_CELLULAR_SETUP_PROVISIONING_PAGE_ACTIVE_TITLE" desc="Title for cellular setup step which indicates that the Chromebook is in the process of connecting to a mobile network.">
Connect to mobile network
</message>
<message name="IDS_CELLULAR_SETUP_FINAL_PAGE_TITLE" desc="Title for the final success screen of cellular setup that tells the user that setup is completed but service is being activated">
Mobile data being activated

@ -26,7 +26,14 @@ constexpr LocalizedString kLocalizedStringsWithoutPlaceholders[] = {
{"simDetectPageErrorTitle", IDS_CELLULAR_SETUP_SIM_DETECT_PAGE_ERROR_TITLE},
{"simDetectPageErrorMessage",
IDS_CELLULAR_SETUP_SIM_DETECT_PAGE_ERROR_MESSAGE},
{"provisioningPageTitle", IDS_CELLULAR_SETUP_PROVISIONING_PAGE_TITLE},
{"provisioningPageLoadingTitle",
IDS_CELLULAR_SETUP_PROVISIONING_PAGE_LOADING_TITLE},
{"provisioningPageActiveTitle",
IDS_CELLULAR_SETUP_PROVISIONING_PAGE_ACTIVE_TITLE},
{"provisioningPageErrorTitle",
IDS_CELLULAR_SETUP_PROVISIONING_PAGE_ERROR_TITLE},
{"provisioningPageErrorMessage",
IDS_CELLULAR_SETUP_PROVISIONING_PAGE_ERROR_MESSAGE},
{"finalPageTitle", IDS_CELLULAR_SETUP_FINAL_PAGE_TITLE},
{"finalPageMessage", IDS_CELLULAR_SETUP_FINAL_PAGE_MESSAGE},
{"finalPageErrorTitle", IDS_CELLULAR_SETUP_FINAL_PAGE_ERROR_TITLE},

@ -236,6 +236,7 @@
"channel": "stable",
"contexts": ["webui"],
"matches": [
"chrome://cellular-setup/*",
"chrome://chrome-signin/*",
"chrome://discards/*",
"chrome://hats/*",

@ -232,6 +232,7 @@
"chrome://add-supervision/*",
"chrome://assistant-optin/*",
"chrome://cast/*",
"chrome://cellular-setup/*",
"chrome://discards/*",
"chrome://extensions-frame/*", // TODO(dbeam): still needed?
"chrome://extensions/*",
@ -652,6 +653,7 @@
"matches": [
"chrome://add-supervision/*",
"chrome://assistant-optin/*",
"chrome://cellular-setup/*",
"chrome://chrome-signin/*",
"chrome://discards/*",
"chrome://hats/*",
@ -672,6 +674,7 @@
"matches": [
"chrome://add-supervision/*",
"chrome://assistant-optin/*",
"chrome://cellular-setup/*",
"chrome://chrome-signin/*",
"chrome://discards/*",
"chrome://hats/*",
@ -690,6 +693,7 @@
"matches": [
"chrome://add-supervision/*",
"chrome://assistant-optin/*",
"chrome://cellular-setup/*",
"chrome://chrome-signin/*",
"chrome://discards/*",
"chrome://hats/*",

@ -47,6 +47,11 @@ js_library("webview_post_util") {
js_library("provisioning_page") {
deps = [
":base_page",
":webview_post_util",
]
externs_list = [
"$externs_path/chrome_extensions.js",
"$externs_path/webview_tag.js",
]
}

@ -23,7 +23,11 @@
selected="[[selectedPageName_]]"
selected-item="{{selectedPage_}}">
<sim-detect-page show-error="[[showError_]]"></sim-detect-page>
<provisioning-page show-error="[[showError_]]"></provisioning-page>
<provisioning-page show-error="{{showError_}}"
cellular-metadata="[[cellularMetadata_]]"
on-carrier-portal-loaded="onCarrierPortalLoaded_"
on-carrier-portal-result="onCarrierPortalResult_">
</provisioning-page>
<final-page show-error="[[showError_]]"></final-page>
</iron-pages>
<button-bar show-try-again-button="[[showTryAgainButton_]]"

@ -40,7 +40,7 @@ cr.define('cellularSetup', function() {
// The portal is a website served by the mobile carrier.
if (state === State.WAITING_FOR_PORTAL_TO_LOAD) {
return 5000; // 5 seconds.
return 10000; // 10 seconds.
}
// Finishing activation only requires sending a D-Bus message to Shill.
@ -99,6 +99,16 @@ Polymer({
*/
showError_: {type: Boolean, value: false},
/**
* Cellular metadata received via the onActivationStarted() callback. If
* that callback has not occurred, this field is null.
* @private {?chromeos.cellularSetup.mojom.CellularMetadata}
*/
cellularMetadata_: {
type: Object,
value: null,
},
/**
* Whether try again should be shown in the button bar.
* @private {boolean}
@ -149,13 +159,6 @@ Polymer({
*/
currentTimeoutId_: null,
/**
* Cellular metadata received via the onActivationStarted() callback. If that
* callback has not occurred, this field is null.
* @private {?chromeos.cellularSetup.mojom.CellularMetadata}
*/
cellularMetadata_: null,
/**
* Handler used to communicate state updates back to the CellularSetup
* service.
@ -320,6 +323,7 @@ Polymer({
this.activationDelegateReceiver_.$.close();
this.activationDelegateReceiver_ = null;
this.carrierPortalHandler_ = null;
this.cellularMetadata_ = null;
},
/** @private */
@ -330,6 +334,24 @@ Polymer({
this.currentTimeoutId_ = null;
},
/** @private */
onCarrierPortalLoaded_: function() {
this.state_ = cellularSetup.State.WAITING_FOR_USER_PAYMENT;
this.carrierPortalHandler_.onCarrierPortalStatusChange(
chromeos.cellularSetup.mojom.CarrierPortalStatus
.kPortalLoadedWithoutPaidUser);
},
/**
* @param {!CustomEvent<boolean>} event
* @private
*/
onCarrierPortalResult_: function(event) {
const success = event.detail;
this.state_ = success ? cellularSetup.State.ACTIVATION_SUCCESS :
cellularSetup.State.ACTIVATION_FAILURE;
},
/** @private */
onBackwardNavRequested_: function() {
// TODO(azeemarshad): Add back navigation.

@ -2,13 +2,47 @@
<link rel="import" href="chrome://resources/html/i18n_behavior.html">
<link rel="import" href="chrome://resources/cr_components/chromeos/cellular_setup/base_page.html">
<link rel="import" href="chrome://resources/cr_components/chromeos/cellular_setup/webview_post_util.html">
<link rel="import" href="chrome://resources/cr_elements/hidden_style_css.html">
<link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout-classes.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-spinner/paper-spinner-lite.html">
<dom-module id="provisioning-page">
<template>
<base-page title="[[i18n('provisioningPageTitle')]]">
<div slot="page-body">
<!-- TODO(azeemarshad): Add webview and error screen -->
[[i18n('provisioningPageTitle')]]
<style include="iron-flex cr-hidden-style">
paper-spinner-lite {
height: 200px;
width: 200px;
}
#portalContainer {
height: 100%;
width: 100%;
}
#error-icon-container {
background-image: -webkit-image-set(
url(error_1x.png) 1x,
url(error_2x.png) 2x);
background-position: center center;
background-repeat: no-repeat;
height: 100%;
width: 100%;
}
</style>
<base-page title="[[getPageTitle_(
showError, carrierName_, hasCarrierPortalLoaded_)]]"
message="[[getPageMessage_(showError)]]">
<div slot="page-body" class="layout horizontal center-center">
<paper-spinner-lite active
hidden$="[[!shouldShowSpinner_(
showError, hasCarrierPortalLoaded_)]]">
</paper-spinner-lite>
<div id="portalContainer"
hidden$="[[!shouldShowPortal_(
showError, hasCarrierPortalLoaded_)]]">
</div>
<div id="error-icon-container" hidden$="[[!showError]]"></div>
</div>
</base-page>
</template>

@ -21,6 +21,189 @@ Polymer({
showError: {
type: Boolean,
value: false,
notify: true,
},
/**
* Metadata used to open carrier provisioning portal. Expected to start as
* null, then change to a valid object.
* @type {?chromeos.cellularSetup.mojom.CellularMetadata}
*/
cellularMetadata: {
type: Object,
value: null,
observer: 'onCellularMetadataChanged_',
},
/**
* Whether the carrier portal has completed being loaded.
* @private {boolean}
*/
hasCarrierPortalLoaded_: {
type: Boolean,
value: false,
},
/**
* The last carrier name provided via |cellularMetadata|.
* @private {string}
*/
carrierName_: {
type: String,
value: '',
},
},
/**
* @return {string}
* @private
*/
getPageTitle_: function() {
if (this.showError) {
return this.i18n('provisioningPageErrorTitle', this.carrierName_);
}
if (this.hasCarrierPortalLoaded_) {
return this.i18n('provisioningPageActiveTitle');
}
return this.i18n('provisioningPageLoadingTitle', this.carrierName_);
},
/**
* @return {string}
* @private
*/
getPageMessage_: function() {
if (this.showError) {
return this.i18n('provisioningPageErrorMessage', this.carrierName_);
}
return '';
},
/**
* @return {boolean}
* @private
*/
shouldShowSpinner_: function() {
return !this.showError && !this.hasCarrierPortalLoaded_;
},
/**
* @return {boolean}
* @private
*/
shouldShowPortal_: function() {
return !this.showError && this.hasCarrierPortalLoaded_;
},
/**
* @return {?WebView}
* @private
*/
getPortalWebview: function() {
return /** @type {?WebView} */ (this.$$('webview'));
},
/** @private */
onCellularMetadataChanged_: function() {
// Once |cellularMetadata| has been set, load the carrier provisioning page.
if (this.cellularMetadata) {
this.carrierName_ = this.cellularMetadata.carrier;
this.loadPortal_();
return;
}
// If |cellularMetadata| is now null, the page should be reset so that a new
// attempt can begin.
this.resetPage_();
},
/** @private */
loadPortal_: function() {
assert(!!this.cellularMetadata);
assert(!this.getPortalWebview());
const portalWebview =
/** @type {!WebView} */ (document.createElement('webview'));
this.$.portalContainer.appendChild(portalWebview);
portalWebview.addEventListener(
'loadabort', this.onPortalLoadAbort_.bind(this));
portalWebview.addEventListener(
'loadstop', this.onPortalLoadStop_.bind(this));
window.addEventListener('message', this.onMessageReceived_.bind(this));
// Setting a <webview>'s "src" attribute triggers a GET request, but some
// carrier portals require a POST request instead. If data is provided for a
// POST request body, use a utility function to load the webview.
if (this.cellularMetadata.paymentPostData) {
webviewPost.util.postDeviceDataToWebview(
portalWebview, this.cellularMetadata.paymentUrl.url,
this.cellularMetadata.paymentPostData);
return;
}
// Otherwise, use a normal GET request by specifying the "src".
portalWebview.src = this.cellularMetadata.paymentUrl.url;
},
/** @private */
resetPage_: function() {
this.hasCarrierPortalLoaded_ = false;
// Remove the portal from the DOM if it exists.
const portalWebview = this.getPortalWebview();
if (portalWebview) {
portalWebview.remove();
}
},
/** @private */
onPortalLoadAbort_: function(event) {
this.showError = true;
},
/** @private */
onPortalLoadStop_: function() {
if (this.hasCarrierPortalLoaded_) {
return;
}
this.hasCarrierPortalLoaded_ = true;
this.fire('carrier-portal-loaded');
// When the portal loads, it expects to receive a message from this frame
// alerting it that loading has completed successfully.
this.getPortalWebview().contentWindow.postMessage(
{msg: 'loadedInWebview'}, this.cellularMetadata.paymentUrl.url);
},
/**
* @param {!Event} event
* @private
*/
onMessageReceived_: function(event) {
const messageType = /** @type {string} */ (event.data.type);
const status = /** @type {string} */ (event.data.status);
// The <webview> requested information about this device. Reply by posting a
// message back to it.
if (messageType == 'requestDeviceInfoMsg') {
this.getPortalWebview().contentWindow.postMessage(
{
carrier: this.cellularMetadata.carrier,
MEID: this.cellularMetadata.meid,
IMEI: this.cellularMetadata.imei,
MDN: this.cellularMetadata.mdn
},
this.cellularMetadata.paymentUrl.url);
return;
}
// The <webview> provided an update on the status of the activation attempt.
if (messageType == 'reportTransactionStatusMsg') {
const success = status == 'ok';
this.fire('on-carrier-portal-result', success);
return;
}
},
});