Commit d90a982c authored by Jesse Schettler's avatar Jesse Schettler Committed by Commit Bot

scanning: Add scan button to scanning app

Add a scan button to the scanning app. When the button is clicked, use
the ScanService to perform a scan with the selected scanner and
settings.

Bug: 1059779
Change-Id: I52231a5a49fa01a2b56e42bcf2f9842fdf54ddf1
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2437103
Auto-Submit: Jesse Schettler <jschettler@chromium.org>
Reviewed-by: default avatarJimmy Gong <jimmyxgong@chromium.org>
Commit-Queue: Jesse Schettler <jschettler@chromium.org>
Cr-Commit-Position: refs/heads/master@{#814535}
parent 2e16d4ca
...@@ -11,6 +11,12 @@ import {setScanServiceForTesting} from 'chrome://scanning/mojo_interface_provide ...@@ -11,6 +11,12 @@ import {setScanServiceForTesting} from 'chrome://scanning/mojo_interface_provide
import {ScannerArr} from 'chrome://scanning/scanning_app_types.js'; import {ScannerArr} from 'chrome://scanning/scanning_app_types.js';
import {getSourceTypeString, tokenToString} from 'chrome://scanning/scanning_app_util.js'; import {getSourceTypeString, tokenToString} from 'chrome://scanning/scanning_app_util.js';
const ColorMode = {
BLACK_AND_WHITE: chromeos.scanning.mojom.ColorMode.kBlackAndWhite,
GRAYSCALE: chromeos.scanning.mojom.ColorMode.kGrayscale,
COLOR: chromeos.scanning.mojom.ColorMode.kColor,
};
const SourceType = { const SourceType = {
FLATBED: chromeos.scanning.mojom.SourceType.kFlatbed, FLATBED: chromeos.scanning.mojom.SourceType.kFlatbed,
ADF_SIMPLEX: chromeos.scanning.mojom.SourceType.kAdfSimplex, ADF_SIMPLEX: chromeos.scanning.mojom.SourceType.kAdfSimplex,
...@@ -65,12 +71,21 @@ class FakeScanService { ...@@ -65,12 +71,21 @@ class FakeScanService {
/** @private {!ScannerArr} */ /** @private {!ScannerArr} */
this.scanners_ = []; this.scanners_ = [];
/**
* @private {!Map<!mojoBase.mojom.UnguessableToken,
* !chromeos.scanning.mojom.ScannerCapabilities>}
*/
this.capabilities_ = new Map();
this.resetForTest(); this.resetForTest();
} }
resetForTest() { resetForTest() {
this.scanners_ = []; this.scanners_ = [];
this.capabilities_ = new Map();
this.resolverMap_.set('getScanners', new PromiseResolver()); this.resolverMap_.set('getScanners', new PromiseResolver());
this.resolverMap_.set('getScannerCapabilities', new PromiseResolver());
this.resolverMap_.set('scan', new PromiseResolver());
} }
/** /**
...@@ -113,6 +128,14 @@ class FakeScanService { ...@@ -113,6 +128,14 @@ class FakeScanService {
this.scanners_ = this.scanners_.concat(scanner); this.scanners_ = this.scanners_.concat(scanner);
} }
/**
* @param {!Map<!mojoBase.mojom.UnguessableToken,
* !chromeos.scanning.mojom.ScannerCapabilities>} capabilities
*/
setCapabilities(capabilities) {
this.capabilities_ = capabilities;
}
// scanService methods: // scanService methods:
/** @return {!Promise<{scanners: !ScannerArr}>} */ /** @return {!Promise<{scanners: !ScannerArr}>} */
...@@ -122,11 +145,35 @@ class FakeScanService { ...@@ -122,11 +145,35 @@ class FakeScanService {
resolve({scanners: this.scanners_ || []}); resolve({scanners: this.scanners_ || []});
}); });
} }
/**
* @param {!mojoBase.mojom.UnguessableToken} scanner_id
* @return {!Promise<{capabilities:
* !chromeos.scanning.mojom.ScannerCapabilities}>}
*/
getScannerCapabilities(scanner_id) {
return new Promise(resolve => {
this.methodCalled('getScannerCapabilities');
resolve({capabilities: this.capabilities_.get(scanner_id)});
});
}
/**
* @param {!mojoBase.mojom.UnguessableToken} scanner_id
* @param {!chromeos.scanning.mojom.ScanSettings} settings
* @return {!Promise<{success: boolean}>}
*/
scan(scanner_id, settings) {
return new Promise(resolve => {
this.methodCalled('scan');
resolve({success: true});
});
}
} }
suite('ScanningAppTest', () => { suite('ScanningAppTest', () => {
/** @type {?ScanningAppElement} */ /** @type {?ScanningAppElement} */
let page = null; let scanningApp = null;
/** @type {?chromeos.scanning.mojom.ScanServiceRemote} */ /** @type {?chromeos.scanning.mojom.ScanServiceRemote} */
let fakeScanService_; let fakeScanService_;
...@@ -138,16 +185,100 @@ suite('ScanningAppTest', () => { ...@@ -138,16 +185,100 @@ suite('ScanningAppTest', () => {
setup(function() { setup(function() {
PolymerTest.clearBody(); PolymerTest.clearBody();
page = document.createElement('scanning-app');
document.body.appendChild(page);
}); });
teardown(function() { teardown(function() {
page.remove(); fakeScanService_.resetForTest();
page = null; scanningApp.remove();
scanningApp = null;
}); });
test('MainPageLoaded', () => {}); /**
* @param {!ScannerArr} scanners
* @param {!Map<!mojoBase.mojom.UnguessableToken,
* !chromeos.scanning.mojom.ScannerCapabilities>} capabilities
* @return {!Promise}
*/
function initializeScanningApp(scanners, capabilities) {
fakeScanService_.setScanners(scanners);
fakeScanService_.setCapabilities(capabilities);
scanningApp = document.createElement('scanning-app');
document.body.appendChild(scanningApp);
assert(!!scanningApp);
return fakeScanService_.whenCalled('getScanners');
}
test('Scan', () => {
const firstScannerId = {high: 0, low: 1};
const firstScannerName = 'Scanner 1';
const secondScannerId = {high: 0, low: 2};
const secondScannerName = 'Scanner 2';
const expectedScanners = [
createScanner(firstScannerId, firstScannerName),
createScanner(secondScannerId, secondScannerName)
];
const firstCapabilities = {
sources: [
{type: SourceType.FLATBED, name: 'platen'},
{type: SourceType.ADF_DUPLEX, name: 'adf duplex'}
],
colorModes: [ColorMode.BLACK_AND_WHITE, ColorMode.COLOR],
resolutions: [75, 100, 300]
};
const secondCapabilities = {
sources: [{type: SourceType.ADF_SIMPLEX, name: 'adf simplex'}],
colorModes: [ColorMode.GRAYSCALE],
resolutions: [150, 600]
};
let capabilities = new Map();
capabilities.set(firstScannerId, firstCapabilities);
capabilities.set(secondScannerId, secondCapabilities);
return initializeScanningApp(expectedScanners, capabilities)
.then(() => {
return fakeScanService_.whenCalled('getScannerCapabilities');
})
.then(() => {
assertEquals(
tokenToString(firstScannerId), scanningApp.selectedScannerId);
assertEquals(
firstCapabilities.sources[0].name, scanningApp.selectedSource);
// Before the scan button is clicked, the settings and scan button
// should be enabled, and there should be no scan status.
const scannerSelect = scanningApp.$$('#scannerSelect').$$('select');
assertFalse(scannerSelect.disabled);
const sourceSelect = scanningApp.$$('#sourceSelect').$$('select');
assertFalse(sourceSelect.disabled);
const scanButton = scanningApp.$$('#scanButton');
assertFalse(scanButton.disabled);
const statusText = scanningApp.$$('#statusText');
assertEquals('', statusText.textContent.trim());
scanButton.click();
// After the scan button is clicked, the settings and scan button
// should be disabled, and the scan status should indicate that
// scanning is in progress.
assertTrue(scannerSelect.disabled);
assertTrue(sourceSelect.disabled);
assertTrue(scanButton.disabled);
assertEquals('Scanning...', statusText.textContent.trim());
return fakeScanService_.whenCalled('scan');
})
.then(() => {
// After scanning is complete, the settings and scan button should be
// enabled, and the scan status should indicate that scanning is
// complete.
assertFalse(scanningApp.$$('#scannerSelect').$$('select').disabled);
assertFalse(scanningApp.$$('#sourceSelect').$$('select').disabled);
assertFalse(scanningApp.$$('#scanButton').disabled);
assertEquals(
'Scan complete! File(s) saved to My files.',
scanningApp.$$('#statusText').textContent.trim());
});
});
}); });
suite('ScannerSelectTest', () => { suite('ScannerSelectTest', () => {
......
...@@ -43,12 +43,14 @@ Polymer({ ...@@ -43,12 +43,14 @@ Polymer({
loaded: Boolean, loaded: Boolean,
settingsDisabled: Boolean,
/** @private */ /** @private */
disabled_: Boolean, disabled_: Boolean,
}, },
observers: [ observers: [
'updateDisabled_(scanners.length)', 'updateDisabled_(scanners.length, settingsDisabled)',
], ],
/** /**
...@@ -73,11 +75,12 @@ Polymer({ ...@@ -73,11 +75,12 @@ Polymer({
}, },
/** /**
* Disables the dropdown based on the number of available scanners. * Disables the dropdown if settings are disabled or the number of available
* @param {number} numScanners * scanners is less than the number of required scanners.
* @private * @private
*/ */
updateDisabled_(numScanners) { updateDisabled_() {
this.disabled_ = numScanners < NUM_REQUIRED_SCANNERS; this.disabled_ =
this.settingsDisabled || this.scanners.length < NUM_REQUIRED_SCANNERS;
}, },
}); });
<div id="header"></div> <div id="header"></div>
<div> <div>
<scanner-select scanners="[[scanners_]]" loaded="[[loaded_]]" <scanner-select id="scannerSelect" scanners="[[scanners_]]"
loaded="[[loaded_]]" settings-disabled="[[settingsDisabled_]]"
selected-scanner-id="{{selectedScannerId}}"></scanner-select> selected-scanner-id="{{selectedScannerId}}"></scanner-select>
</div> </div>
<div> <div>
<source-select sources="[[capabilities_.sources]]" <source-select id="sourceSelect" sources="[[capabilities_.sources]]"
settings-disabled="[[settingsDisabled_]]"
selected-source="{{selectedSource}}"></source-select> selected-source="{{selectedSource}}"></source-select>
</div> </div>
<!-- TODO(jschettler): Replace button label with finalized i18n string. -->
<cr-button id="scanButton" on-click="onScanClick_"
disabled$="[[scanButtonDisabled_]]">
Scan
</cr-button>
<p id="statusText">[[statusText_]]</p>
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'chrome://resources/cr_elements/cr_button/cr_button.m.js';
import 'chrome://resources/mojo/mojo/public/mojom/base/big_buffer.mojom-lite.js'; import 'chrome://resources/mojo/mojo/public/mojom/base/big_buffer.mojom-lite.js';
import 'chrome://resources/mojo/mojo/public/mojom/base/string16.mojom-lite.js'; import 'chrome://resources/mojo/mojo/public/mojom/base/string16.mojom-lite.js';
import 'chrome://resources/mojo/mojo/public/mojom/base/unguessable_token.mojom-lite.js'; import 'chrome://resources/mojo/mojo/public/mojom/base/unguessable_token.mojom-lite.js';
...@@ -50,6 +51,24 @@ Polymer({ ...@@ -50,6 +51,24 @@ Polymer({
/** @type {?string} */ /** @type {?string} */
selectedSource: String, selectedSource: String,
/**
* @type {?string}
* @private
*/
statusText_: String,
/** @private */
settingsDisabled_: {
type: Boolean,
value: false,
},
/** @private */
scanButtonDisabled_: {
type: Boolean,
value: true,
},
/** @private */ /** @private */
loaded_: { loaded_: {
type: Boolean, type: Boolean,
...@@ -80,6 +99,8 @@ Polymer({ ...@@ -80,6 +99,8 @@ Polymer({
// Set the first source as the selected source since it will be the first // Set the first source as the selected source since it will be the first
// option in the dropdown. // option in the dropdown.
this.selectedSource = this.capabilities_.sources[0].name; this.selectedSource = this.capabilities_.sources[0].name;
this.scanButtonDisabled_ = false;
}, },
/** /**
...@@ -112,8 +133,51 @@ Polymer({ ...@@ -112,8 +133,51 @@ Polymer({
return; return;
} }
this.scanButtonDisabled_ = true;
this.scanService_ this.scanService_
.getScannerCapabilities(this.scannerIds_.get(selectedScannerId)) .getScannerCapabilities(this.scannerIds_.get(selectedScannerId))
.then(this.onCapabilitiesReceived_.bind(this)); .then(this.onCapabilitiesReceived_.bind(this));
}, },
/** @private */
onScanClick_() {
if (!this.selectedScannerId || !this.selectedSource) {
// TODO(jschettler): Replace status text with finalized i18n strings.
this.statusText_ = 'Failed to start scan.';
return;
}
this.statusText_ = 'Scanning...';
this.settingsDisabled_ = true;
this.scanButtonDisabled_ = true;
// TODO(jschettler): Set color mode and resolution using the selected values
// when the corresponding dropdowns are added.
const settings = {
'sourceName': this.selectedSource,
'colorMode': chromeos.scanning.mojom.ColorMode.kColor,
'resolutionDpi': 100,
};
this.scanService_
.scan(this.scannerIds_.get(this.selectedScannerId), settings)
.then(
/*@type {!{success: boolean}}*/ (response) => {
this.onScanCompleted_(response)});
},
/**
* @param {!{success: boolean}} response
* @private
*/
onScanCompleted_(response) {
if (response.success) {
this.statusText_ = 'Scan complete! File(s) saved to My files.';
} else {
this.statusText_ = 'Scan failed.';
}
this.settingsDisabled_ = false;
this.scanButtonDisabled_ = false;
},
}); });
...@@ -39,12 +39,14 @@ Polymer({ ...@@ -39,12 +39,14 @@ Polymer({
notify: true, notify: true,
}, },
settingsDisabled: Boolean,
/** @private */ /** @private */
disabled_: Boolean, disabled_: Boolean,
}, },
observers: [ observers: [
'updateDisabled_(sources.length)', 'updateDisabled_(sources.length, settingsDisabled)',
], ],
/** /**
...@@ -57,11 +59,12 @@ Polymer({ ...@@ -57,11 +59,12 @@ Polymer({
}, },
/** /**
* Disables the dropdown based on the number of available sources. * Disables the dropdown if settings are disabled or the number of available
* @param {number} numSources * sources is less than the number of required sources.
* @private * @private
*/ */
updateDisabled_(numSources) { updateDisabled_() {
this.disabled_ = numSources < NUM_REQUIRED_SOURCES; this.disabled_ =
this.settingsDisabled || this.sources.length < NUM_REQUIRED_SOURCES;
}, },
}); });
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