Commit a3e0119f authored by Gordon Seto's avatar Gordon Seto Committed by Commit Bot

[CrOS Settings] Add invalid activation code UI.

Add UI for informing when an activation code is invalid in the
activation code page.

Screenshot:
https://screenshot.googleplex.com/3gLCppUSwZbqovc.png

Bug: 1093185
Change-Id: Ieb9959cdbd0dd754454eaa69d5c5f4ac5453c8fe
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2555917
Commit-Queue: Gordon Seto <gordonseto@google.com>
Reviewed-by: default avatarAzeem Arshad <azeemarshad@chromium.org>
Reviewed-by: default avatarKyle Horimoto <khorimoto@chromium.org>
Cr-Commit-Position: refs/heads/master@{#830714}
parent f23603e5
......@@ -336,6 +336,9 @@
<message name="IDS_CELLULAR_SETUP_ESIM_PAGE_SCAN_QR_CODE_RETRY" desc="Label for button that uses the camera to rescan for QR codes when clicked.">
use camera again
</message>
<message name="IDS_CELLULAR_SETUP_ESIM_PAGE_SCAN_QR_CODE_INVALID" desc="Label informing the user that the activation code is invalid.">
Invalid code, please try again.
</message>
<message name="IDS_CELLULAR_SETUP_ESTABLISH_NETWORK_CONNECTION" desc="Message, informing user that a network connection is being established during cellular setup">
Establishing network connection ...
</message>
......
03f243f8e9d5b4a127aa449581efe8fcde8e583b
\ No newline at end of file
......@@ -56,6 +56,7 @@ constexpr webui::LocalizedString kLocalizedStringsWithoutPlaceholders[] = {
{"useCamera", IDS_CELLULAR_SETUP_ESIM_PAGE_USE_CAMERA},
{"scanQRCodeSuccess", IDS_CELLULAR_SETUP_ESIM_PAGE_SCAN_QR_CODE_SUCCESS},
{"qrCodeRetry", IDS_CELLULAR_SETUP_ESIM_PAGE_SCAN_QR_CODE_RETRY},
{"scanQrCodeInvalid", IDS_CELLULAR_SETUP_ESIM_PAGE_SCAN_QR_CODE_INVALID},
{"profileListPageMessage", IDS_CELLULAR_SETUP_PROFILE_LIST_PAGE_MESSAGE}};
} // namespace
......
......@@ -38,19 +38,23 @@ suite('CrComponentsActivationCodePageTest', function() {
const startScanningContainer =
activationCodePage.$$('#startScanningContainer');
const startScanningButton = activationCodePage.$$('#startScanningButton');
const scanSuccessContainer = activationCodePage.$$('#scanSuccessContainer');
const scanFinishContainer = activationCodePage.$$('#scanFinishContainer');
const switchCameraButton = activationCodePage.$$('#switchCameraButton');
const scanSuccessContainer = activationCodePage.$$('#scanSuccessContainer');
const scanFailureContainer = activationCodePage.$$('#scanFailureContainer');
assertTrue(!!video);
assertTrue(!!startScanningContainer);
assertTrue(!!startScanningButton);
assertTrue(!!scanSuccessContainer);
assertTrue(!!scanFinishContainer);
assertTrue(!!switchCameraButton);
assertTrue(!!scanSuccessContainer);
assertTrue(!!scanFailureContainer);
// Initial state should only be showing the start scanning UI.
assertFalse(startScanningContainer.hidden);
assertTrue(video.hidden);
assertTrue(scanSuccessContainer.hidden);
assertTrue(scanFinishContainer.hidden);
assertTrue(switchCameraButton.hidden);
// Click the start scanning button.
......@@ -60,18 +64,55 @@ suite('CrComponentsActivationCodePageTest', function() {
// The video should be visible and start scanning UI hidden.
assertFalse(video.hidden);
assertTrue(startScanningContainer.hidden);
assertTrue(scanSuccessContainer.hidden);
assertTrue(scanFinishContainer.hidden);
assertTrue(switchCameraButton.hidden);
// Mock detecting an activation code.
activationCodePage.$$('#activationCode').value = 'ACTIVATION_CODE';
await flushAsync();
// The scanSuccessContainer should now be visible, video and start scanning
// UI hidden.
// The scanFinishContainer and scanSuccessContainer should now be visible,
// video, start scanning UI and scanFailureContainer hidden.
assertFalse(scanFinishContainer.hidden);
assertTrue(startScanningContainer.hidden);
assertTrue(video.hidden);
assertFalse(scanSuccessContainer.hidden);
assertTrue(scanFailureContainer.hidden);
// Mock an invalid activation code.
activationCodePage.showError = true;
// The scanFinishContainer and scanFailureContainer should now be visible,
// video, start scanning UI and scanSuccessContainer hidden.
assertFalse(scanFinishContainer.hidden);
assertTrue(startScanningContainer.hidden);
assertTrue(video.hidden);
assertTrue(scanSuccessContainer.hidden);
assertFalse(scanFailureContainer.hidden);
// Enter a new activation code
activationCodePage.$$('#activationCode').value = 'ACTIVATION_CODE 2';
await flushAsync();
// The scanFinishContainer and scanSuccessContainer should now be visible,
// video, start scanning UI and scanFailureContainer hidden.
assertFalse(scanFinishContainer.hidden);
assertTrue(startScanningContainer.hidden);
assertTrue(video.hidden);
assertFalse(scanSuccessContainer.hidden);
assertTrue(scanFailureContainer.hidden);
assertFalse(activationCodePage.showError);
// Mock another invalid activation code.
activationCodePage.showError = true;
// The scanFinishContainer and scanFailureContainer should now be visible,
// video, start scanning UI and scanSuccessContainer hidden.
assertFalse(scanFinishContainer.hidden);
assertTrue(startScanningContainer.hidden);
assertTrue(video.hidden);
assertTrue(scanSuccessContainer.hidden);
assertFalse(scanFailureContainer.hidden);
});
test('Switch camera button states', async function() {
......
......@@ -81,9 +81,8 @@ suite('CrComponentsEsimFlowUiTest', function() {
eSimPage.selectedESimPageName_ ===
cellular_setup.ESimPageName.ACTIVATION_CODE &&
eSimPage.selectedESimPageName_ === activationCodePage.id);
// TODO(crbug.com/1093185) We don't have a way to show the error on the DOM
// right now. Check internal property for now.
assertTrue(eSimPage.showError_);
assertTrue(activationCodePage.$$('#scanSuccessContainer').hidden);
assertFalse(activationCodePage.$$('#scanFailureContainer').hidden);
});
test('No eSIM profile flow valid activation code', async function() {
......
......@@ -35,15 +35,6 @@
background-color: transparent;
}
#scanSuccessMessage {
color: green;
font-size: medium;
}
#scanSuccessMessage:hover {
cursor: default;
}
.center {
left: 50%;
position: absolute;
......@@ -61,24 +52,44 @@
width: 20px;
}
#useCameraAgainButton {
font-weight: 500;
left: 50%;
margin-top: 16px;
transform: translateX(-50%);
}
#scanSuccessImage {
.scan-finish-image {
height: 20px;
position: absolute;
width: 20px;
}
#scanSuccessMessage {
.scan-finish-message {
padding-inline-end: 0;
padding-inline-start: 30px;
}
.scan-finish-message:hover {
cursor: default;
}
#scanSuccessContainer {
margin-bottom: 8px;
}
#scanSuccessMessage {
color: green;
font-size: medium;
}
#scanFailureContainer {
margin-bottom: 4px;
}
#scanFailureMessage {
color: var(--google-red-600);
}
#useCameraAgainButton {
display: block;
font-weight: 500;
text-align: center;
}
#switchCameraButton {
background-color: rgba(0, 0, 0, 0.04);
border-radius: 4px;
......@@ -124,15 +135,25 @@
[[i18n('useCamera')]]
</cr-button>
</div>
<div class="center" id="scanSuccessContainer"
hidden$="[[isUiElementHidden_(UiElement.SCAN_SUCCESS, state_)]]">
<div class="center" id="scanFinishContainer"
hidden$="[[isUiElementHidden_(UiElement.SCAN_FINISH, state_)]]">
<div>
<img id="scanSuccessImage"
src="activation_code_page_checked.svg"
aria-hidden="true">
<span class="label" id="scanSuccessMessage">
[[i18n('scanQRCodeSuccess')]]
</span>
<div id="scanSuccessContainer"
hidden$="[[isUiElementHidden_(UiElement.SCAN_SUCCESS, state_)]]">
<img class="scan-finish-image"
src="activation_code_page_checked.svg">
<span class="label scan-finish-message" id="scanSuccessMessage">
[[i18n('scanQRCodeSuccess')]]
</span>
</div>
<div id="scanFailureContainer"
hidden$="[[isUiElementHidden_(UiElement.SCAN_FAILURE, state_)]]">
<img class="scan-finish-image"
src="activation_code_page_error.svg">
<span class="label scan-finish-message" id="scanFailureMessage">
[[i18n('scanQrCodeInvalid')]]
</span>
</div>
</div>
<cr-button id="useCameraAgainButton"
on-click="startScanning_">
......
......@@ -16,14 +16,17 @@ const PageState = {
SWITCHING_CAM_USER_TO_ENVIRONMENT: 4,
SWITCHING_CAM_ENVIRONMENT_TO_USER: 5,
SUCCESS: 6,
FAILURE: 7,
};
/** @enum {number} */
const UiElement = {
START_SCANNING: 1,
VIDEO: 2,
SCAN_SUCCESS: 3,
SWITCH_CAMERA: 4,
SWITCH_CAMERA: 3,
SCAN_FINISH: 4,
SCAN_SUCCESS: 5,
SCAN_FAILURE: 6,
};
/**
......@@ -42,6 +45,12 @@ Polymer({
observer: 'onActivationCodeChanged_',
},
showError: {
type: Boolean,
notify: true,
observer: 'onShowErrorChanged_',
},
/**
* @type {!PageState}
* @private
......@@ -49,6 +58,7 @@ Polymer({
state_: {
type: Object,
value: PageState,
observer: 'onStateChanged_',
},
/** @private */
......@@ -225,12 +235,13 @@ Polymer({
onActivationCodeChanged_() {
const activationCode = this.validateActivationCode_(this.activationCode);
this.fire('activation-code-updated', {activationCode: activationCode});
// TODO(crbug.com/1093185): Handle if activation code is invalid.
if (activationCode) {
if (this.stream_) {
this.stream_.getTracks()[0].stop();
}
this.state_ = PageState.SUCCESS;
} else {
this.state_ = PageState.FAILURE;
}
},
......@@ -260,6 +271,20 @@ Polymer({
this.startScanning_();
},
/** @private */
onShowErrorChanged_() {
if (this.showError) {
this.state_ = PageState.FAILURE;
}
},
/** @private */
onStateChanged_() {
if (this.state_ !== PageState.FAILURE) {
this.showError = false;
}
},
/**
* @param {UiElement} uiElement
* @param {PageState} state
......@@ -273,12 +298,16 @@ Polymer({
case UiElement.VIDEO:
return state !== PageState.SCANNING_USER_FACING &&
state !== PageState.SCANNING_ENVIRONMENT_FACING;
case UiElement.SCAN_SUCCESS:
return state !== PageState.SUCCESS;
case UiElement.SWITCH_CAMERA:
const isScanning = state === PageState.SCANNING_USER_FACING ||
state === PageState.SCANNING_ENVIRONMENT_FACING;
return !(isScanning && hasMultipleCameras);
case UiElement.SCAN_FINISH:
return state !== PageState.SUCCESS && state !== PageState.FAILURE;
case UiElement.SCAN_SUCCESS:
return state !== PageState.SUCCESS;
case UiElement.SCAN_FAILURE:
return state !== PageState.FAILURE;
}
},
......
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M9 10h2V6H9v4zm1-8c-4.416 0-8 3.584-8 8s3.584 8 8 8 8-3.584 8-8-3.584-8-8-8zm0 14c-3.308 0-6-2.693-6-6 0-3.308 2.692-6 6-6 3.307 0 6 2.692 6 6 0 3.307-2.693 6-6 6zm-1-2h2v-2H9v2z" fill="#D93025"/></svg>
\ No newline at end of file
......@@ -31,7 +31,8 @@
selected-profiles="{{selectedProfiles_}}">
</profile-discovery-list-page>
<activation-code-page id="activationCodePage"
activation-code="{{activationCode_}}">
activation-code="{{activationCode_}}"
show-error="{{showError_}}">
</activation-code-page>
<final-page
id="finalPage"
......
......@@ -175,8 +175,6 @@ cr.define('cellular_setup', function() {
handleProfileInstallResponse_(response) {
// TODO(crbug.com/1093185) Handle
// confirmation code if needed.
// TODO(crbug.com/1093185) If response.result ===
// kErrorInvalidActivationCode, show error in activation code page.
this.showError_ = response.result !==
chromeos.cellularSetup.mojom.ProfileInstallResult.kSuccess;
if (response.result ===
......
......@@ -13,12 +13,14 @@
url(final_page_success_2x.png) 2x);
background-position: center center;
background-repeat: no-repeat;
background-size: contain;
}
.error[slot='page-body'] {
background-image: -webkit-image-set(
url(error_1x.png) 1x,
url(error_2x.png) 2x);
background-size: contain;
}
</style>
<base-page title="[[getTitle_(showError)]]"
......
......@@ -39,6 +39,10 @@
file="cr_components/chromeos/cellular_setup/activation_code_page_switch_camera.svg"
type="BINDATA"
compress="gzip" />
<include name="IDR_WEBUI_CHROMEOS_CELLULAR_SETUP_ACTIVATION_CODE_PAGE_ERROR_SVG"
file="cr_components/chromeos/cellular_setup/activation_code_page_error.svg"
type="BINDATA"
compress="gzip" />
<include name="IDR_WEBUI_CHROMEOS_CELLULAR_SETUP_ERROR_1X_PNG"
file="cr_components/chromeos/cellular_setup/error_1x.png"
type="BINDATA"
......
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