Commit 0d79dadc authored by Jimmy Gong's avatar Jimmy Gong Committed by Commit Bot

Delete print job history when browser history is deleted

- Print history will be deleted when a user clears their
  browser history.
- Future CL will include a policy pref to disable this.
- Implements PrintJobsObserver Mojo interface.
- This CL is the initial work to start supporting automatic
  updates to the print management app.
- Feature is disabled until policy is implemented.

Bug: 1053704
Test: browser_tests
Change-Id: I283fce0eb1a850bce4b577aeaa71059b11fe1acb
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2204524
Commit-Queue: jimmy gong <jimmyxgong@chromium.org>
Reviewed-by: default avatarZentaro Kavanagh <zentaro@chromium.org>
Reviewed-by: default avatarRegan Hsu <hsuregan@chromium.org>
Reviewed-by: default avatarTom Sepez <tsepez@chromium.org>
Reviewed-by: default avatarBailey Berro <baileyberro@chromium.org>
Reviewed-by: default avatarKyle Horimoto <khorimoto@chromium.org>
Cr-Commit-Position: refs/heads/master@{#773942}
parent f9bfb7cb
...@@ -8,6 +8,10 @@ ...@@ -8,6 +8,10 @@
#include "chrome/browser/chromeos/printing/history/print_job_history_service.h" #include "chrome/browser/chromeos/printing/history/print_job_history_service.h"
#include "chrome/browser/chromeos/printing/history/print_job_history_service_factory.h" #include "chrome/browser/chromeos/printing/history/print_job_history_service_factory.h"
#include "chrome/browser/chromeos/printing/print_management/print_job_info_mojom_conversions.h" #include "chrome/browser/chromeos/printing/print_management/print_job_info_mojom_conversions.h"
#include "chrome/browser/history/history_service_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "components/history/core/browser/history_service.h"
#include "components/history/core/browser/history_types.h"
#include "content/public/browser/browser_context.h" #include "content/public/browser/browser_context.h"
namespace chromeos { namespace chromeos {
...@@ -15,14 +19,27 @@ namespace printing { ...@@ -15,14 +19,27 @@ namespace printing {
namespace print_management { namespace print_management {
using chromeos::printing::proto::PrintJobInfo; using chromeos::printing::proto::PrintJobInfo;
using history::DeletionInfo;
using history::HistoryService;
using printing_manager::mojom::PrintingMetadataProvider; using printing_manager::mojom::PrintingMetadataProvider;
using printing_manager::mojom::PrintJobInfoPtr; using printing_manager::mojom::PrintJobInfoPtr;
using printing_manager::mojom::PrintJobsObserver;
PrintingManager::PrintingManager( PrintingManager::PrintingManager(
PrintJobHistoryService* print_job_history_service) PrintJobHistoryService* print_job_history_service,
: print_job_history_service_(print_job_history_service) {} HistoryService* history_service)
: print_job_history_service_(print_job_history_service),
history_service_(history_service) {
if (history_service_) {
history_service_->AddObserver(this);
}
}
PrintingManager::~PrintingManager() = default; PrintingManager::~PrintingManager() {
if (history_service_) {
history_service_->RemoveObserver(this);
}
}
void PrintingManager::GetPrintJobs(GetPrintJobsCallback callback) { void PrintingManager::GetPrintJobs(GetPrintJobsCallback callback) {
print_job_history_service_->GetPrintJobs( print_job_history_service_->GetPrintJobs(
...@@ -31,8 +48,38 @@ void PrintingManager::GetPrintJobs(GetPrintJobsCallback callback) { ...@@ -31,8 +48,38 @@ void PrintingManager::GetPrintJobs(GetPrintJobsCallback callback) {
} }
void PrintingManager::DeleteAllPrintJobs(DeleteAllPrintJobsCallback callback) { void PrintingManager::DeleteAllPrintJobs(DeleteAllPrintJobsCallback callback) {
// TODO(crbug/1053704): This is a NO-OP, implement when policy is available. if (IsHistoryDeletionPreventedByPolicy()) {
std::move(callback).Run(/*success=*/true); std::move(callback).Run(/*success=*/false);
return;
}
print_job_history_service_->DeleteAllPrintJobs(std::move(callback));
}
void PrintingManager::ObservePrintJobs(
mojo::PendingRemote<PrintJobsObserver> observer,
ObservePrintJobsCallback callback) {
print_job_observers_.Add(std::move(observer));
std::move(callback).Run();
}
void PrintingManager::OnURLsDeleted(HistoryService* history_service,
const DeletionInfo& deletion_info) {
// We only handle deletion of all history because it is an explicit action by
// user to explicitly remove all their history-related content.
if (IsHistoryDeletionPreventedByPolicy() || !deletion_info.IsAllHistory()) {
return;
}
DeleteAllPrintJobs(base::BindOnce(&PrintingManager::OnPrintJobsDeleted,
weak_ptr_factory_.GetWeakPtr()));
}
void PrintingManager::OnPrintJobsDeleted(bool success) {
DCHECK(success) << "Clearing print jobs failed unexpectedly.";
for (auto& observer : print_job_observers_) {
observer->OnAllPrintJobsDeleted();
}
} }
void PrintingManager::OnPrintJobsRetrieved( void PrintingManager::OnPrintJobsRetrieved(
...@@ -55,8 +102,16 @@ void PrintingManager::BindInterface( ...@@ -55,8 +102,16 @@ void PrintingManager::BindInterface(
receiver_.Bind(std::move(pending_receiver)); receiver_.Bind(std::move(pending_receiver));
} }
// TODO(crbug/1053704): Implement the policy and check for the policy here.
bool PrintingManager::IsHistoryDeletionPreventedByPolicy() {
NOTIMPLEMENTED()
<< "IsHistoryDeletionPreventedByPolicy is not yet implemented";
return true;
}
void PrintingManager::Shutdown() { void PrintingManager::Shutdown() {
receiver_.reset(); receiver_.reset();
weak_ptr_factory_.InvalidateWeakPtrs();
} }
} // namespace print_management } // namespace print_management
......
...@@ -5,22 +5,30 @@ ...@@ -5,22 +5,30 @@
#ifndef CHROME_BROWSER_CHROMEOS_PRINTING_PRINT_MANAGEMENT_PRINTING_MANAGER_H_ #ifndef CHROME_BROWSER_CHROMEOS_PRINTING_PRINT_MANAGEMENT_PRINTING_MANAGER_H_
#define CHROME_BROWSER_CHROMEOS_PRINTING_PRINT_MANAGEMENT_PRINTING_MANAGER_H_ #define CHROME_BROWSER_CHROMEOS_PRINTING_PRINT_MANAGEMENT_PRINTING_MANAGER_H_
#include "base/memory/weak_ptr.h"
#include "chrome/browser/chromeos/printing/history/print_job_info.pb.h" #include "chrome/browser/chromeos/printing/history/print_job_info.pb.h"
#include "chromeos/components/print_management/mojom/printing_manager.mojom.h" #include "chromeos/components/print_management/mojom/printing_manager.mojom.h"
#include "components/history/core/browser/history_service_observer.h"
#include "components/keyed_service/core/keyed_service.h" #include "components/keyed_service/core/keyed_service.h"
#include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/receiver.h" #include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote_set.h"
namespace chromeos { namespace chromeos {
class DeletionInfo;
class HistoryService;
class PrintJobHistoryService; class PrintJobHistoryService;
namespace printing { namespace printing {
namespace print_management { namespace print_management {
class PrintingManager class PrintingManager
: public printing_manager::mojom::PrintingMetadataProvider, : public printing_manager::mojom::PrintingMetadataProvider,
public KeyedService { public KeyedService,
public history::HistoryServiceObserver {
public: public:
explicit PrintingManager(PrintJobHistoryService* print_job_history_service); PrintingManager(PrintJobHistoryService* print_job_history_service,
history::HistoryService* history_service);
~PrintingManager() override; ~PrintingManager() override;
PrintingManager(const PrintingManager&) = delete; PrintingManager(const PrintingManager&) = delete;
...@@ -29,6 +37,9 @@ class PrintingManager ...@@ -29,6 +37,9 @@ class PrintingManager
// printing_manager::mojom::PrintingMetadataProvider: // printing_manager::mojom::PrintingMetadataProvider:
void GetPrintJobs(GetPrintJobsCallback callback) override; void GetPrintJobs(GetPrintJobsCallback callback) override;
void DeleteAllPrintJobs(DeleteAllPrintJobsCallback callback) override; void DeleteAllPrintJobs(DeleteAllPrintJobsCallback callback) override;
void ObservePrintJobs(
mojo::PendingRemote<printing_manager::mojom::PrintJobsObserver> observer,
ObservePrintJobsCallback callback) override;
void BindInterface( void BindInterface(
mojo::PendingReceiver<printing_manager::mojom::PrintingMetadataProvider> mojo::PendingReceiver<printing_manager::mojom::PrintingMetadataProvider>
...@@ -38,14 +49,41 @@ class PrintingManager ...@@ -38,14 +49,41 @@ class PrintingManager
// KeyedService: // KeyedService:
void Shutdown() override; void Shutdown() override;
// history::HistoryServiceObserver:
void OnURLsDeleted(history::HistoryService* history_service,
const history::DeletionInfo& deletion_info) override;
void OnPrintJobsRetrieved(GetPrintJobsCallback callback, void OnPrintJobsRetrieved(GetPrintJobsCallback callback,
bool success, bool success,
std::vector<chromeos::printing::proto::PrintJobInfo> std::vector<chromeos::printing::proto::PrintJobInfo>
print_job_info_protos); print_job_info_protos);
// Callback function that is called when the print jobs are cleared from the
// local database.
void OnPrintJobsDeleted(bool success);
// Returns true if the policy pref is enabled to prevent history deletions.
// TODO(crbug/1053704): Add the policy pref and implement this function.
bool IsHistoryDeletionPreventedByPolicy();
// Set of PrintJobsObserver mojom::remotes, each remote is bound to a
// renderer process receiver. Automatically handles removing disconnected
// receivers.
mojo::RemoteSet<printing_manager::mojom::PrintJobsObserver>
print_job_observers_;
mojo::Receiver<printing_manager::mojom::PrintingMetadataProvider> receiver_{ mojo::Receiver<printing_manager::mojom::PrintingMetadataProvider> receiver_{
this}; this};
chromeos::PrintJobHistoryService* print_job_history_service_; // NOT OWNED.
// Not owned, this is the intermediate layer to interact with the print
// job local database.
chromeos::PrintJobHistoryService* print_job_history_service_;
// Not owned, this provides the necessary observers to observe when browser
// history has been cleared.
history::HistoryService* history_service_;
base::WeakPtrFactory<PrintingManager> weak_ptr_factory_{this};
}; };
} // namespace print_management } // namespace print_management
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include "chrome/browser/chromeos/printing/history/print_job_history_service_factory.h" #include "chrome/browser/chromeos/printing/history/print_job_history_service_factory.h"
#include "chrome/browser/chromeos/printing/print_management/printing_manager.h" #include "chrome/browser/chromeos/printing/print_management/printing_manager.h"
#include "chrome/browser/history/history_service_factory.h"
#include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile.h"
#include "components/keyed_service/content/browser_context_dependency_manager.h" #include "components/keyed_service/content/browser_context_dependency_manager.h"
...@@ -30,6 +31,7 @@ PrintingManagerFactory::PrintingManagerFactory() ...@@ -30,6 +31,7 @@ PrintingManagerFactory::PrintingManagerFactory()
"PrintingManager", "PrintingManager",
BrowserContextDependencyManager::GetInstance()) { BrowserContextDependencyManager::GetInstance()) {
DependsOn(PrintJobHistoryServiceFactory::GetInstance()); DependsOn(PrintJobHistoryServiceFactory::GetInstance());
DependsOn(HistoryServiceFactory::GetInstance());
} }
PrintingManagerFactory::~PrintingManagerFactory() = default; PrintingManagerFactory::~PrintingManagerFactory() = default;
...@@ -37,7 +39,9 @@ PrintingManagerFactory::~PrintingManagerFactory() = default; ...@@ -37,7 +39,9 @@ PrintingManagerFactory::~PrintingManagerFactory() = default;
KeyedService* PrintingManagerFactory::BuildServiceInstanceFor( KeyedService* PrintingManagerFactory::BuildServiceInstanceFor(
content::BrowserContext* context) const { content::BrowserContext* context) const {
return new PrintingManager( return new PrintingManager(
PrintJobHistoryServiceFactory::GetForBrowserContext(context)); PrintJobHistoryServiceFactory::GetForBrowserContext(context),
HistoryServiceFactory::GetForProfile(Profile::FromBrowserContext(context),
ServiceAccessType::EXPLICIT_ACCESS));
} }
} // namespace print_management } // namespace print_management
......
...@@ -97,13 +97,23 @@ class FakePrintingMetadataProvider { ...@@ -97,13 +97,23 @@ class FakePrintingMetadataProvider {
/** @type {!Array<chromeos.printing.printingManager.mojom.PrintJobInfo>} */ /** @type {!Array<chromeos.printing.printingManager.mojom.PrintJobInfo>} */
this.printJobs_ = []; this.printJobs_ = [];
/**
* @type {?chromeos.printing.printingManager.mojom.PrintJobsObserverRemote}
*/
this.printJobsObserverRemote;
this.resetForTest(); this.resetForTest();
} }
resetForTest() { resetForTest() {
this.printJobs_ = []; this.printJobs_ = [];
if (this.printJobsObserverRemote) {
this.printJobsObserverRemote = null;
}
this.resolverMap_.set('getPrintJobs', new PromiseResolver()); this.resolverMap_.set('getPrintJobs', new PromiseResolver());
this.resolverMap_.set('deleteAllPrintJobs', new PromiseResolver()); this.resolverMap_.set('deleteAllPrintJobs', new PromiseResolver());
this.resolverMap_.set('observePrintJobs', new PromiseResolver());
} }
/** /**
...@@ -151,6 +161,11 @@ class FakePrintingMetadataProvider { ...@@ -151,6 +161,11 @@ class FakePrintingMetadataProvider {
this.printJobs_ = this.printJobs_.concat(job); this.printJobs_ = this.printJobs_.concat(job);
} }
simulatePrintJobsDeletedfromDatabase() {
this.printJobs_ = [];
this.printJobsObserverRemote.onAllPrintJobsDeleted();
}
// printingMetadataProvider methods // printingMetadataProvider methods
/** /**
...@@ -172,6 +187,19 @@ class FakePrintingMetadataProvider { ...@@ -172,6 +187,19 @@ class FakePrintingMetadataProvider {
resolve({success: true}); resolve({success: true});
}); });
} }
/**
* @param
* {!chromeos.printing.printingManager.mojom.PrintJobsObserverRemote} remote
* @return {!Promise}
*/
observePrintJobs(remote) {
return new Promise(resolve => {
this.printJobsObserverRemote = remote;
this.methodCalled('observePrintJobs');
resolve();
});
}
} }
suite('PrintManagementTest', () => { suite('PrintManagementTest', () => {
...@@ -203,6 +231,7 @@ suite('PrintManagementTest', () => { ...@@ -203,6 +231,7 @@ suite('PrintManagementTest', () => {
/** /**
* @param {?Array<!chromeos.printing.printingManager.mojom.PrintJobInfo>} * @param {?Array<!chromeos.printing.printingManager.mojom.PrintJobInfo>}
* printJobs * printJobs
* @return {!Promise}
*/ */
function initializePrintManagementApp(printJobs) { function initializePrintManagementApp(printJobs) {
mojoApi_.setPrintJobs(printJobs); mojoApi_.setPrintJobs(printJobs);
...@@ -210,6 +239,7 @@ suite('PrintManagementTest', () => { ...@@ -210,6 +239,7 @@ suite('PrintManagementTest', () => {
document.body.appendChild(page); document.body.appendChild(page);
assert(!!page); assert(!!page);
flush(); flush();
return mojoApi_.whenCalled('observePrintJobs');
} }
test('PrintHistoryListIsSortedReverseChronologically', () => { test('PrintHistoryListIsSortedReverseChronologically', () => {
...@@ -228,21 +258,27 @@ suite('PrintManagementTest', () => { ...@@ -228,21 +258,27 @@ suite('PrintManagementTest', () => {
// Initialize with a reversed array of |expectedArr|, since we expect the // Initialize with a reversed array of |expectedArr|, since we expect the
// app to sort the list when it first loads. Since reverse() mutates the // app to sort the list when it first loads. Since reverse() mutates the
// original array, use a copy array to prevent mutating |expectedArr|. // original array, use a copy array to prevent mutating |expectedArr|.
initializePrintManagementApp(expectedArr.slice().reverse()); return initializePrintManagementApp(expectedArr.slice().reverse())
return mojoApi_.whenCalled('getPrintJobs').then(() => { .then(() => {
flush(); return mojoApi_.whenCalled('getPrintJobs');
verifyPrintJobs(expectedArr, getPrintJobEntries(page)); })
}); .then(() => {
flush();
verifyPrintJobs(expectedArr, getPrintJobEntries(page));
});
}); });
test('ClearAllButtonDisabledWhenNoPrintJobsSaved', () => { test('ClearAllButtonDisabledWhenNoPrintJobsSaved', () => {
// Initialize with no saved print jobs, expect the clear all button to be // Initialize with no saved print jobs, expect the clear all button to be
// disabled. // disabled.
initializePrintManagementApp(/*printJobs=*/[]); return initializePrintManagementApp(/*printJobs=*/[])
return mojoApi_.whenCalled('getPrintJobs').then(() => { .then(() => {
flush(); return mojoApi_.whenCalled('getPrintJobs');
assertTrue(page.$$('#clearAllButton').disabled); })
}); .then(() => {
flush();
assertTrue(page.$$('#clearAllButton').disabled);
});
}); });
test('ClearAllPrintHistory', () => { test('ClearAllPrintHistory', () => {
...@@ -258,8 +294,10 @@ suite('PrintManagementTest', () => { ...@@ -258,8 +294,10 @@ suite('PrintManagementTest', () => {
new Date(Date.UTC('February 7, 2020 03:24:00')), 'nameC'), new Date(Date.UTC('February 7, 2020 03:24:00')), 'nameC'),
]; ];
initializePrintManagementApp(expectedArr); return initializePrintManagementApp(expectedArr)
return mojoApi_.whenCalled('getPrintJobs') .then(() => {
return mojoApi_.whenCalled('getPrintJobs');
})
.then(() => { .then(() => {
flush(); flush();
verifyPrintJobs(expectedArr, getPrintJobEntries(page)); verifyPrintJobs(expectedArr, getPrintJobEntries(page));
...@@ -283,6 +321,39 @@ suite('PrintManagementTest', () => { ...@@ -283,6 +321,39 @@ suite('PrintManagementTest', () => {
assertTrue(page.$$('#clearAllButton').disabled); assertTrue(page.$$('#clearAllButton').disabled);
}); });
}); });
test('PrintJobDeletesFromObserver', () => {
const expectedArr = [
createJobEntry(
'fileA', 'titleA', CompletionStatus.PRINTED,
new Date(Date('February 5, 2020 03:24:00')), 'nameA'),
createJobEntry(
'fileB', 'titleB', CompletionStatus.PRINTED,
new Date(Date('February 6, 2020 03:24:00')), 'nameB'),
createJobEntry(
'fileC', 'titleC', CompletionStatus.PRINTED,
new Date(Date('February 7, 2020 03:24:00')), 'nameC'),
];
return initializePrintManagementApp(expectedArr)
.then(() => {
return mojoApi_.whenCalled('getPrintJobs');
})
.then(() => {
flush();
verifyPrintJobs(expectedArr, getPrintJobEntries(page));
// Simulate observer call that signals all print jobs have been
// deleted. Expect the UI to retrieve an empty list of print jobs.
mojoApi_.simulatePrintJobsDeletedfromDatabase();
return mojoApi_.whenCalled('getPrintJobs');
})
.then(() => {
flush();
verifyPrintJobs(/*expected=*/[], getPrintJobEntries(page));
assertTrue(page.$$('#clearAllButton').disabled);
});
});
}); });
suite('PrintJobEntryTest', () => { suite('PrintJobEntryTest', () => {
......
...@@ -42,11 +42,25 @@ struct PrintJobInfo { ...@@ -42,11 +42,25 @@ struct PrintJobInfo {
url.mojom.Url printer_uri; url.mojom.Url printer_uri;
}; };
// Observer interface that sends remote updates to the print management app UI
// receiver.
interface PrintJobsObserver {
// Notifies that the local print job database has been cleared.
OnAllPrintJobsDeleted();
};
// Provides APIs to retrieve print metadata information. This API is exposed // Provides APIs to retrieve print metadata information. This API is exposed
// only to the Print Management App (chrome://print-management). Interfaces are // only to the Print Management App (chrome://print-management). Interfaces are
// implemented by a browser service. Interacts with PrintHistory API to retrieve // implemented by a browser service. Interacts with PrintHistory API to retrieve
// print job metadatas. // print job metadatas.
interface PrintingMetadataProvider { interface PrintingMetadataProvider {
// Takes in a remote so that the implementer binds it and send notifications
// to the receiver in the print management app. This is to set up automatic
// updates from the browser process to the renderer process.
// (print management app UI). This is guaranteed to not send remote updates
// to disconnected receivers.
ObservePrintJobs(pending_remote<PrintJobsObserver> observer) => ();
// Returns an array of PrintJobInfo. This is the main function to retrieve // Returns an array of PrintJobInfo. This is the main function to retrieve
// the print history of a device. // the print history of a device.
GetPrintJobs() => (array<PrintJobInfo> print_jobs); GetPrintJobs() => (array<PrintJobInfo> print_jobs);
......
...@@ -59,14 +59,16 @@ Polymer({ ...@@ -59,14 +59,16 @@ Polymer({
}, },
/** /**
* @param {boolean} success * @param {!{success: boolean}} clearedHistoryResult
* @private * @private
*/ */
onClearedHistory_(success) { onClearedHistory_(clearedHistoryResult) {
// There should realistically be no way that clearing the history can fail. if (clearedHistoryResult.success) {
assert(success); this.fire('all-history-cleared');
}
this.fire('all-history-cleared'); // Failed case results in a no op and closes the dialog.
// |clearedHistoryResult| is temporarily set to false until the policy
// to control print job history deletions is implemented.
this.$.clearDialog.close(); this.$.clearDialog.close();
}, },
}); });
\ No newline at end of file
...@@ -43,6 +43,13 @@ Polymer({ ...@@ -43,6 +43,13 @@ Polymer({
*/ */
mojoInterfaceProvider_: null, mojoInterfaceProvider_: null,
/**
* Receiver responsible for observing print job updates notification events.
* @private {
* ?chromeos.printing.printingManager.mojom.PrintJobsObserverReceiver}
*/
printJobsObserverReceiver_: null,
properties: { properties: {
/** /**
* @type {!Array<!chromeos.printing.printingManager.mojom.PrintJobInfo>} * @type {!Array<!chromeos.printing.printingManager.mojom.PrintJobInfo>}
...@@ -82,7 +89,37 @@ Polymer({ ...@@ -82,7 +89,37 @@ Polymer({
}, },
/** @override */ /** @override */
ready() { attached() {
this.startObservingPrintJobs_();
},
/** @override */
detached() {
this.printJobsObserverReceiver_.$.close();
},
/** @private */
startObservingPrintJobs_() {
this.printJobsObserverReceiver_ =
new chromeos.printing.printingManager.mojom.PrintJobsObserverReceiver
(
/**
* @type {!chromeos.printing.printingManager.mojom.
* PrintJobsObserverInterface}
*/
(this));
this.mojoInterfaceProvider_.observePrintJobs(
this.printJobsObserverReceiver_.$.bindNewPipeAndPassRemote())
.then(() => {
this.getPrintJobs_();
});
},
/**
* Overrides chromeos.printing.printingManager.mojom.
* PrintJobsObserverInterface
*/
onAllPrintJobsDeleted() {
this.getPrintJobs_(); this.getPrintJobs_();
}, },
......
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