Commit 4d50e3ec authored by Gavin Williams's avatar Gavin Williams Committed by Commit Bot

scanning: Return saved file path on scan completion

On completion of a scan job, return the file path of the last scanned
file to the Scanning App. Will be used to open the Files app.

Bug: 1059779
Change-Id: Ia3d33155daf472fc65fa2a959c068caddb3bff2f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2545743Reviewed-by: default avatarKyle Horimoto <khorimoto@chromium.org>
Reviewed-by: default avatarZentaro Kavanagh <zentaro@chromium.org>
Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Reviewed-by: default avatarJesse Schettler <jschettler@chromium.org>
Commit-Queue: Gavin Williams <gavinwill@chromium.org>
Cr-Commit-Position: refs/heads/master@{#830744}
parent 237ca5a8
...@@ -97,7 +97,8 @@ TEST_F(DocumentScanScanFunctionTest, ScanImageError) { ...@@ -97,7 +97,8 @@ TEST_F(DocumentScanScanFunctionTest, ScanImageError) {
TEST_F(DocumentScanScanFunctionTest, Success) { TEST_F(DocumentScanScanFunctionTest, Success) {
GetLorgnetteScannerManager()->SetGetScannerNamesResponse({kTestScannerName}); GetLorgnetteScannerManager()->SetGetScannerNamesResponse({kTestScannerName});
GetLorgnetteScannerManager()->SetScanResponse("PrettyPicture"); const std::vector<std::string> scan_data = {"PrettyPicture"};
GetLorgnetteScannerManager()->SetScanResponse(scan_data);
std::unique_ptr<base::DictionaryValue> result(RunFunctionAndReturnDictionary( std::unique_ptr<base::DictionaryValue> result(RunFunctionAndReturnDictionary(
function_.get(), "[{\"mimeTypes\": [\"image/png\"]}]")); function_.get(), "[{\"mimeTypes\": [\"image/png\"]}]"));
ASSERT_NE(nullptr, result.get()); ASSERT_NE(nullptr, result.get());
......
...@@ -36,18 +36,19 @@ void FakeLorgnetteScannerManager::Scan(const std::string& scanner_name, ...@@ -36,18 +36,19 @@ void FakeLorgnetteScannerManager::Scan(const std::string& scanner_name,
PageCallback page_callback, PageCallback page_callback,
CompletionCallback completion_callback) { CompletionCallback completion_callback) {
if (scan_data_.has_value()) { if (scan_data_.has_value()) {
constexpr uint32_t page_number = 1; uint32_t page_number = 1;
if (progress_callback) { for (const std::string& page_data : scan_data_.value()) {
for (const uint32_t progress : {7, 22, 40, 42, 59, 74, 95}) { if (progress_callback) {
base::ThreadTaskRunnerHandle::Get()->PostTask( for (const uint32_t progress : {7, 22, 40, 42, 59, 74, 95}) {
FROM_HERE, base::ThreadTaskRunnerHandle::Get()->PostTask(
base::BindOnce(progress_callback, progress, page_number)); FROM_HERE,
base::BindOnce(progress_callback, progress, page_number));
}
} }
}
base::ThreadTaskRunnerHandle::Get()->PostTask( base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, FROM_HERE, base::BindOnce(page_callback, page_data, page_number++));
base::BindOnce(page_callback, scan_data_.value(), page_number)); }
} }
base::ThreadTaskRunnerHandle::Get()->PostTask( base::ThreadTaskRunnerHandle::Get()->PostTask(
...@@ -72,7 +73,7 @@ void FakeLorgnetteScannerManager::SetGetScannerCapabilitiesResponse( ...@@ -72,7 +73,7 @@ void FakeLorgnetteScannerManager::SetGetScannerCapabilitiesResponse(
} }
void FakeLorgnetteScannerManager::SetScanResponse( void FakeLorgnetteScannerManager::SetScanResponse(
const base::Optional<std::string>& scan_data) { const base::Optional<std::vector<std::string>>& scan_data) {
scan_data_ = scan_data; scan_data_ = scan_data;
} }
......
...@@ -45,12 +45,13 @@ class FakeLorgnetteScannerManager final : public LorgnetteScannerManager { ...@@ -45,12 +45,13 @@ class FakeLorgnetteScannerManager final : public LorgnetteScannerManager {
scanner_capabilities); scanner_capabilities);
// Sets the response returned by Scan(). // Sets the response returned by Scan().
void SetScanResponse(const base::Optional<std::string>& scan_data); void SetScanResponse(
const base::Optional<std::vector<std::string>>& scan_data);
private: private:
std::vector<std::string> scanner_names_; std::vector<std::string> scanner_names_;
base::Optional<lorgnette::ScannerCapabilities> scanner_capabilities_; base::Optional<lorgnette::ScannerCapabilities> scanner_capabilities_;
base::Optional<std::string> scan_data_; base::Optional<std::vector<std::string>> scan_data_;
}; };
} // namespace chromeos } // namespace chromeos
......
...@@ -52,14 +52,13 @@ std::string PngToJpg(const std::string& png_img) { ...@@ -52,14 +52,13 @@ std::string PngToJpg(const std::string& png_img) {
return std::string(jpg_img.begin(), jpg_img.end()); return std::string(jpg_img.begin(), jpg_img.end());
} }
// Saves |scanned_image| to a file after converting it if necessary. Returns // Saves |scanned_image| to a file after converting it if necessary. Returns the
// true if the save succeeds. // file path to the saved file if the save succeeds.
bool SavePage(const base::FilePath& scan_to_path, base::FilePath SavePage(const base::FilePath& scan_to_path,
const mojo_ipc::FileType file_type, const mojo_ipc::FileType file_type,
std::string scanned_image, std::string scanned_image,
uint32_t page_number, uint32_t page_number,
const base::Time::Exploded& start_time) { const base::Time::Exploded& start_time) {
std::string filename;
std::string file_ext; std::string file_ext;
switch (file_type) { switch (file_type) {
case mojo_ipc::FileType::kPng: case mojo_ipc::FileType::kPng:
...@@ -69,25 +68,25 @@ bool SavePage(const base::FilePath& scan_to_path, ...@@ -69,25 +68,25 @@ bool SavePage(const base::FilePath& scan_to_path,
file_ext = "jpg"; file_ext = "jpg";
scanned_image = PngToJpg(scanned_image); scanned_image = PngToJpg(scanned_image);
if (scanned_image.empty()) if (scanned_image.empty())
return false; return base::FilePath();
break; break;
default: default:
LOG(ERROR) << "Selected file type not supported."; LOG(ERROR) << "Selected file type not supported.";
return false; return base::FilePath();
} }
filename = base::StringPrintf( const std::string filename = base::StringPrintf(
"scan_%02d%02d%02d-%02d%02d%02d_%d.%s", start_time.year, start_time.month, "scan_%02d%02d%02d-%02d%02d%02d_%d.%s", start_time.year, start_time.month,
start_time.day_of_month, start_time.hour, start_time.minute, start_time.day_of_month, start_time.hour, start_time.minute,
start_time.second, page_number, file_ext.c_str()); start_time.second, page_number, file_ext.c_str());
const auto file_path = scan_to_path.Append(filename); const auto file_path = scan_to_path.Append(filename);
if (!base::WriteFile(file_path, scanned_image)) { if (!base::WriteFile(file_path, scanned_image)) {
LOG(ERROR) << "Failed to save scanned image: " << file_path.value().c_str(); LOG(ERROR) << "Failed to save scanned image: " << file_path.value().c_str();
return false; return base::FilePath();
} }
return true; return file_path;
} }
} // namespace } // namespace
...@@ -147,6 +146,7 @@ void ScanService::StartScan( ...@@ -147,6 +146,7 @@ void ScanService::StartScan(
base::Time::Now().LocalExplode(&start_time_); base::Time::Now().LocalExplode(&start_time_);
save_failed_ = false; save_failed_ = false;
last_scanned_file_path_.clear();
lorgnette_scanner_manager_->Scan( lorgnette_scanner_manager_->Scan(
scanner_name, mojo::ConvertTo<lorgnette::ScanSettings>(settings), scanner_name, mojo::ConvertTo<lorgnette::ScanSettings>(settings),
base::BindRepeating(&ScanService::OnProgressPercentReceived, base::BindRepeating(&ScanService::OnProgressPercentReceived,
...@@ -254,13 +254,17 @@ void ScanService::OnCancelCompleted(bool success) { ...@@ -254,13 +254,17 @@ void ScanService::OnCancelCompleted(bool success) {
scan_job_observer_->OnCancelComplete(success); scan_job_observer_->OnCancelComplete(success);
} }
void ScanService::OnPageSaved(bool success) { void ScanService::OnPageSaved(const base::FilePath& saved_file_path) {
if (!success) save_failed_ = save_failed_ || saved_file_path.empty();
save_failed_ = true; last_scanned_file_path_ = save_failed_ ? base::FilePath() : saved_file_path;
} }
void ScanService::OnAllPagesSaved(bool success) { void ScanService::OnAllPagesSaved(bool success) {
scan_job_observer_->OnScanComplete(success && !save_failed_); save_failed_ = !success || save_failed_;
if (save_failed_)
last_scanned_file_path_.clear();
scan_job_observer_->OnScanComplete(!save_failed_, last_scanned_file_path_);
} }
bool ScanService::FilePathSupported(const base::FilePath& file_path) { bool ScanService::FilePathSupported(const base::FilePath& file_path) {
......
...@@ -101,7 +101,7 @@ class ScanService : public scanning::mojom::ScanService, public KeyedService { ...@@ -101,7 +101,7 @@ class ScanService : public scanning::mojom::ScanService, public KeyedService {
void OnCancelCompleted(bool success); void OnCancelCompleted(bool success);
// Called once the task runner finishes saving a page of a scan. // Called once the task runner finishes saving a page of a scan.
void OnPageSaved(bool success); void OnPageSaved(const base::FilePath& saved_file_path);
// Called once the task runner finishes saving the last page of a scan. // Called once the task runner finishes saving the last page of a scan.
void OnAllPagesSaved(bool success); void OnAllPagesSaved(bool success);
...@@ -142,6 +142,9 @@ class ScanService : public scanning::mojom::ScanService, public KeyedService { ...@@ -142,6 +142,9 @@ class ScanService : public scanning::mojom::ScanService, public KeyedService {
// The time a scan was started. Used in filenames when saving scanned images. // The time a scan was started. Used in filenames when saving scanned images.
base::Time::Exploded start_time_; base::Time::Exploded start_time_;
// The file path of the last page scanned in a scan job.
base::FilePath last_scanned_file_path_;
// Task runner used to convert and save scanned images. // Task runner used to convert and save scanned images.
scoped_refptr<base::SequencedTaskRunner> task_runner_; scoped_refptr<base::SequencedTaskRunner> task_runner_;
......
...@@ -66,6 +66,23 @@ lorgnette::ScannerCapabilities CreateLorgnetteScannerCapabilities() { ...@@ -66,6 +66,23 @@ lorgnette::ScannerCapabilities CreateLorgnetteScannerCapabilities() {
return caps; return caps;
} }
// Returns a vector of FilePaths to mimic saved scans.
std::vector<base::FilePath> CreateSavedScanPaths(
const base::FilePath& dir,
const base::Time::Exploded& scan_time,
const std::string& type,
int num_pages_to_scan) {
std::vector<base::FilePath> file_paths;
file_paths.reserve(num_pages_to_scan);
for (int i = 1; i <= num_pages_to_scan; i++) {
file_paths.push_back(dir.Append(base::StringPrintf(
"scan_%02d%02d%02d-%02d%02d%02d_%d.%s", scan_time.year, scan_time.month,
scan_time.day_of_month, scan_time.hour, scan_time.minute,
scan_time.second, i, type.c_str())));
}
return file_paths;
}
} // namespace } // namespace
class FakeScanJobObserver : public mojo_ipc::ScanJobObserver { class FakeScanJobObserver : public mojo_ipc::ScanJobObserver {
...@@ -86,7 +103,11 @@ class FakeScanJobObserver : public mojo_ipc::ScanJobObserver { ...@@ -86,7 +103,11 @@ class FakeScanJobObserver : public mojo_ipc::ScanJobObserver {
page_complete_ = true; page_complete_ = true;
} }
void OnScanComplete(bool success) override { scan_success_ = success; } void OnScanComplete(bool success,
const base::FilePath& last_scanned_file_path) override {
scan_success_ = success;
last_scanned_file_path_ = last_scanned_file_path;
}
void OnCancelComplete(bool success) override { void OnCancelComplete(bool success) override {
cancel_scan_success_ = success; cancel_scan_success_ = success;
...@@ -111,11 +132,17 @@ class FakeScanJobObserver : public mojo_ipc::ScanJobObserver { ...@@ -111,11 +132,17 @@ class FakeScanJobObserver : public mojo_ipc::ScanJobObserver {
// Returns true if the cancel scan request completed successfully. // Returns true if the cancel scan request completed successfully.
bool cancel_scan_success() const { return cancel_scan_success_; } bool cancel_scan_success() const { return cancel_scan_success_; }
// Returns the file path of the file saved last.
base::FilePath last_scanned_file_path() const {
return last_scanned_file_path_;
}
private: private:
uint32_t progress_ = 0; uint32_t progress_ = 0;
bool page_complete_ = false; bool page_complete_ = false;
bool scan_success_ = false; bool scan_success_ = false;
bool cancel_scan_success_ = false; bool cancel_scan_success_ = false;
base::FilePath last_scanned_file_path_;
mojo::Receiver<mojo_ipc::ScanJobObserver> receiver_{this}; mojo::Receiver<mojo_ipc::ScanJobObserver> receiver_{this};
}; };
...@@ -265,7 +292,8 @@ TEST_F(ScanServiceTest, ScanWithBadScannerId) { ...@@ -265,7 +292,8 @@ TEST_F(ScanServiceTest, ScanWithBadScannerId) {
TEST_F(ScanServiceTest, ScanWithUnsupportedFilePath) { TEST_F(ScanServiceTest, ScanWithUnsupportedFilePath) {
fake_lorgnette_scanner_manager_.SetGetScannerNamesResponse( fake_lorgnette_scanner_manager_.SetGetScannerNamesResponse(
{kFirstTestScannerName}); {kFirstTestScannerName});
fake_lorgnette_scanner_manager_.SetScanResponse("TestData"); const std::vector<std::string> scan_data = {"TestData"};
fake_lorgnette_scanner_manager_.SetScanResponse(scan_data);
auto scanners = GetScanners(); auto scanners = GetScanners();
ASSERT_EQ(scanners.size(), 1u); ASSERT_EQ(scanners.size(), 1u);
...@@ -281,7 +309,9 @@ TEST_F(ScanServiceTest, ScanWithUnsupportedFilePath) { ...@@ -281,7 +309,9 @@ TEST_F(ScanServiceTest, ScanWithUnsupportedFilePath) {
TEST_F(ScanServiceTest, Scan) { TEST_F(ScanServiceTest, Scan) {
fake_lorgnette_scanner_manager_.SetGetScannerNamesResponse( fake_lorgnette_scanner_manager_.SetGetScannerNamesResponse(
{kFirstTestScannerName}); {kFirstTestScannerName});
fake_lorgnette_scanner_manager_.SetScanResponse("TestData"); const std::vector<std::string> scan_data = {"TestData1", "TestData2",
"TestData3"};
fake_lorgnette_scanner_manager_.SetScanResponse(scan_data);
auto scanners = GetScanners(); auto scanners = GetScanners();
ASSERT_EQ(scanners.size(), 1u); ASSERT_EQ(scanners.size(), 1u);
...@@ -294,18 +324,20 @@ TEST_F(ScanServiceTest, Scan) { ...@@ -294,18 +324,20 @@ TEST_F(ScanServiceTest, Scan) {
settings.scan_to_path = temp_dir_.GetPath(); settings.scan_to_path = temp_dir_.GetPath();
std::map<std::string, mojo_ipc::FileType> file_types = { std::map<std::string, mojo_ipc::FileType> file_types = {
{"png", mojo_ipc::FileType::kPng}, {"jpg", mojo_ipc::FileType::kJpg}}; {"png", mojo_ipc::FileType::kPng}, {"jpg", mojo_ipc::FileType::kJpg}};
base::FilePath saved_scan_path;
for (const auto& type : file_types) { for (const auto& type : file_types) {
saved_scan_path = temp_dir_.GetPath().Append(base::StringPrintf( const std::vector<base::FilePath> saved_scan_paths = CreateSavedScanPaths(
"scan_%02d%02d%02d-%02d%02d%02d_1.%s", scan_time.year, scan_time.month, temp_dir_.GetPath(), scan_time, type.first, scan_data.size());
scan_time.day_of_month, scan_time.hour, scan_time.minute, for (const auto& saved_scan_path : saved_scan_paths)
scan_time.second, type.first.c_str())); EXPECT_FALSE(base::PathExists(saved_scan_path));
EXPECT_FALSE(base::PathExists(saved_scan_path));
settings.file_type = type.second; settings.file_type = type.second;
EXPECT_TRUE(Scan(scanners[0]->id, settings.Clone())); EXPECT_TRUE(Scan(scanners[0]->id, settings.Clone()));
EXPECT_TRUE(base::PathExists(saved_scan_path)); for (const auto& saved_scan_path : saved_scan_paths)
EXPECT_TRUE(base::PathExists(saved_scan_path));
EXPECT_TRUE(fake_scan_job_observer_.scan_success()); EXPECT_TRUE(fake_scan_job_observer_.scan_success());
EXPECT_EQ(saved_scan_paths.back(),
fake_scan_job_observer_.last_scanned_file_path());
} }
} }
...@@ -313,7 +345,8 @@ TEST_F(ScanServiceTest, Scan) { ...@@ -313,7 +345,8 @@ TEST_F(ScanServiceTest, Scan) {
TEST_F(ScanServiceTest, CancelScanBeforeScanCompletes) { TEST_F(ScanServiceTest, CancelScanBeforeScanCompletes) {
fake_lorgnette_scanner_manager_.SetGetScannerNamesResponse( fake_lorgnette_scanner_manager_.SetGetScannerNamesResponse(
{kFirstTestScannerName}); {kFirstTestScannerName});
fake_lorgnette_scanner_manager_.SetScanResponse("TestData"); const std::vector<std::string> scan_data = {"TestData"};
fake_lorgnette_scanner_manager_.SetScanResponse(scan_data);
auto scanners = GetScanners(); auto scanners = GetScanners();
ASSERT_EQ(scanners.size(), 1u); ASSERT_EQ(scanners.size(), 1u);
......
...@@ -168,7 +168,7 @@ class FakeScanService { ...@@ -168,7 +168,7 @@ class FakeScanService {
* @return {!Promise} * @return {!Promise}
*/ */
simulateScanComplete(success) { simulateScanComplete(success) {
this.scanJobObserverRemote_.onScanComplete(success); this.scanJobObserverRemote_.onScanComplete(success, {'path': ''});
return flushTasks(); return flushTasks();
} }
......
...@@ -103,8 +103,9 @@ interface ScanJobObserver { ...@@ -103,8 +103,9 @@ interface ScanJobObserver {
OnPageComplete(array<uint8> page_data); OnPageComplete(array<uint8> page_data);
// Called when the scan is complete. |success| indicates whether the scan // Called when the scan is complete. |success| indicates whether the scan
// completed successfully. // completed successfully. |last_scanned_file_path| is the file path of
OnScanComplete(bool success); // the last page scanned in a scan job.
OnScanComplete(bool success, mojo_base.mojom.FilePath last_scanned_file_path);
// Called when canceling the current scan job is complete. |success| // Called when canceling the current scan job is complete. |success|
// indicates whether the scan job was cancelled successfully. // indicates whether the scan job was cancelled successfully.
......
...@@ -171,6 +171,13 @@ Polymer({ ...@@ -171,6 +171,13 @@ Polymer({
type: Boolean, type: Boolean,
value: false, value: false,
}, },
/**
* The file path of the last scanned page of a successful scan job. Used to
* open the Files app with the correct file highlighted.
* @private {?mojoBase.mojom.FilePath}
*/
lastScannedFilePath_: Object,
}, },
/** @override */ /** @override */
...@@ -228,9 +235,11 @@ Polymer({ ...@@ -228,9 +235,11 @@ Polymer({
/** /**
* Overrides chromeos.scanning.mojom.ScanJobObserverInterface. * Overrides chromeos.scanning.mojom.ScanJobObserverInterface.
* @param {boolean} success * @param {boolean} success
* @param {!mojoBase.mojom.FilePath} lastScannedFilePath
*/ */
onScanComplete(success) { onScanComplete(success, lastScannedFilePath) {
if (success) { if (success) {
this.lastScannedFilePath_ = lastScannedFilePath;
this.setAppState_(AppState.DONE); this.setAppState_(AppState.DONE);
return; return;
} }
......
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