Commit 48fd6e87 authored by Rouslan Solomakhin's avatar Rouslan Solomakhin Committed by Commit Bot

[Payment Request][Desktop] State initialization task.

This patch refactors the relationship between PaymentRequestDialogView
and PaymentRequestState to be more generic. Instead of waiting for the
state event of fetching all payment instruments (specific), the view now
waits for an initialization task (abstraction) to finish initialization
(generic). This will help to add more initialization tasks in follow up
patches. For example, PaymentRequestSpec will become an initialization
task as well, so the view can wait for the spec to completely
initialized, in case if PaymentRequest.show() was called with a promise.

Bug: 817073
Change-Id: I19c133ab3084a7a26628380135c21abeeb1c7436
Reviewed-on: https://chromium-review.googlesource.com/c/1478090
Commit-Queue: Rouslan Solomakhin <rouslan@chromium.org>
Reviewed-by: default avatarDanyao Wang <danyao@chromium.org>
Cr-Commit-Position: refs/heads/master@{#634710}
parent 5d000c09
...@@ -79,10 +79,13 @@ PaymentRequestDialogView::PaymentRequestDialogView( ...@@ -79,10 +79,13 @@ PaymentRequestDialogView::PaymentRequestDialogView(
AddChildView(view_stack_.get()); AddChildView(view_stack_.get());
SetupSpinnerOverlay(); SetupSpinnerOverlay();
// Show spinner when getting all payment instruments. The spinner will be
// hidden in OnGetAllPaymentInstrumentsFinished. if (!request->state()->IsInitialized()) {
if (!request->state()->is_get_all_instruments_finished()) { request->state()->AddInitializationObserver(this);
request->state()->AddObserver(this); ++number_of_initialization_tasks_;
}
if (number_of_initialization_tasks_ > 0) {
ShowProcessingSpinner(); ShowProcessingSpinner();
} else if (observer_for_testing_) { } else if (observer_for_testing_) {
// When testing, signal that the processing spinner events have passed, even // When testing, signal that the processing spinner events have passed, even
...@@ -233,19 +236,19 @@ void PaymentRequestDialogView::OnSpecUpdated() { ...@@ -233,19 +236,19 @@ void PaymentRequestDialogView::OnSpecUpdated() {
observer_for_testing_->OnSpecDoneUpdating(); observer_for_testing_->OnSpecDoneUpdating();
} }
void PaymentRequestDialogView::OnGetAllPaymentInstrumentsFinished() { void PaymentRequestDialogView::OnInitialized(
InitializationTask* initialization_task) {
initialization_task->RemoveInitializationObserver(this);
if (--number_of_initialization_tasks_ > 0)
return;
HideProcessingSpinner(); HideProcessingSpinner();
if (request_->state()->are_requested_methods_supported()) { if (request_->state()->are_requested_methods_supported()) {
request_->RecordDialogShownEventInJourneyLogger(); request_->RecordDialogShownEventInJourneyLogger();
if (observer_for_testing_) { if (observer_for_testing_)
// The OnGetAllPaymentInstrumentsFinished() method is called if the
// payment instruments were retrieved asynchronously. This method hides
// the "Processing" spinner, so the UI is now ready for interaction. Any
// test that opens UI can now interact with it. The OnDialogOpened() call
// notifies the tests of this event.
observer_for_testing_->OnDialogOpened(); observer_for_testing_->OnDialogOpened();
} }
}
} }
void PaymentRequestDialogView::Pay() { void PaymentRequestDialogView::Pay() {
...@@ -419,17 +422,15 @@ void PaymentRequestDialogView::ShowInitialPaymentSheet() { ...@@ -419,17 +422,15 @@ void PaymentRequestDialogView::ShowInitialPaymentSheet() {
request_->spec(), request_->state(), this), request_->spec(), request_->state(), this),
&controller_map_), &controller_map_),
/* animate = */ false); /* animate = */ false);
if (request_->state()->is_get_all_instruments_finished() &&
request_->state()->are_requested_methods_supported()) { if (number_of_initialization_tasks_ > 0)
return;
if (request_->state()->are_requested_methods_supported()) {
request_->RecordDialogShownEventInJourneyLogger(); request_->RecordDialogShownEventInJourneyLogger();
if (observer_for_testing_) { if (observer_for_testing_)
// The is_get_all_instruments_finished() method returns true if all
// payment instruments were retrieved synchronously. Any test that opens
// UI can now interact with it. The OnDialogOpened() call notifies the
// tests of this event.
observer_for_testing_->OnDialogOpened(); observer_for_testing_->OnDialogOpened();
} }
}
} }
void PaymentRequestDialogView::SetupSpinnerOverlay() { void PaymentRequestDialogView::SetupSpinnerOverlay() {
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "base/callback_forward.h" #include "base/callback_forward.h"
#include "base/macros.h" #include "base/macros.h"
#include "chrome/browser/ui/views/payments/view_stack.h" #include "chrome/browser/ui/views/payments/view_stack.h"
#include "components/payments/content/initialization_task.h"
#include "components/payments/content/payment_request_dialog.h" #include "components/payments/content/payment_request_dialog.h"
#include "components/payments/content/payment_request_spec.h" #include "components/payments/content/payment_request_spec.h"
#include "components/payments/content/payment_request_state.h" #include "components/payments/content/payment_request_state.h"
...@@ -46,7 +47,7 @@ enum class BackNavigationType { ...@@ -46,7 +47,7 @@ enum class BackNavigationType {
class PaymentRequestDialogView : public views::DialogDelegateView, class PaymentRequestDialogView : public views::DialogDelegateView,
public PaymentRequestDialog, public PaymentRequestDialog,
public PaymentRequestSpec::Observer, public PaymentRequestSpec::Observer,
public PaymentRequestState::Observer { public InitializationTask::Observer {
public: public:
class ObserverForTest { class ObserverForTest {
public: public:
...@@ -119,9 +120,8 @@ class PaymentRequestDialogView : public views::DialogDelegateView, ...@@ -119,9 +120,8 @@ class PaymentRequestDialogView : public views::DialogDelegateView,
void OnStartUpdating(PaymentRequestSpec::UpdateReason reason) override; void OnStartUpdating(PaymentRequestSpec::UpdateReason reason) override;
void OnSpecUpdated() override; void OnSpecUpdated() override;
// PaymentRequestState::Observer: // InitializationTask::Observer:
void OnGetAllPaymentInstrumentsFinished() override; void OnInitialized(InitializationTask* initialization_task) override;
void OnSelectedInformationChanged() override {}
void Pay(); void Pay();
void GoBack(); void GoBack();
...@@ -211,6 +211,9 @@ class PaymentRequestDialogView : public views::DialogDelegateView, ...@@ -211,6 +211,9 @@ class PaymentRequestDialogView : public views::DialogDelegateView,
// controller_map_. // controller_map_.
bool being_closed_; bool being_closed_;
// The number of initialization tasks that are not yet initialized.
size_t number_of_initialization_tasks_ = 0;
DISALLOW_COPY_AND_ASSIGN(PaymentRequestDialogView); DISALLOW_COPY_AND_ASSIGN(PaymentRequestDialogView);
}; };
......
...@@ -9,6 +9,8 @@ jumbo_static_library("content") { ...@@ -9,6 +9,8 @@ jumbo_static_library("content") {
"can_make_payment_query_factory.cc", "can_make_payment_query_factory.cc",
"can_make_payment_query_factory.h", "can_make_payment_query_factory.h",
"content_payment_request_delegate.h", "content_payment_request_delegate.h",
"initialization_task.cc",
"initialization_task.h",
"payment_request.cc", "payment_request.cc",
"payment_request.h", "payment_request.h",
"payment_request_converter.cc", "payment_request_converter.cc",
......
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/payments/content/initialization_task.h"
namespace payments {
InitializationTask::Observer::~Observer() = default;
InitializationTask::InitializationTask() = default;
InitializationTask::~InitializationTask() = default;
void InitializationTask::AddInitializationObserver(Observer* observer) {
observers_.AddObserver(observer);
}
void InitializationTask::RemoveInitializationObserver(Observer* observer) {
observers_.RemoveObserver(observer);
}
void InitializationTask::NotifyInitialized() {
DCHECK(!has_notified_);
has_notified_ = true;
for (Observer& observer : observers_) {
observer.OnInitialized(this);
}
}
} // namespace payments
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_PAYMENTS_CONTENT_INITIALIZATION_TASK_H_
#define COMPONENTS_PAYMENTS_CONTENT_INITIALIZATION_TASK_H_
#include "base/macros.h"
#include "base/observer_list.h"
#include "base/observer_list_types.h"
namespace payments {
// An interface for a task that takes time to initialize. Useful for monitoring
// initialization of several asynchronous tasks.
//
// Sample usage:
//
// class Foo : public InitializationTask {
// public:
// Foo() {}
//
// ~Foo() override {}
//
// // InitializationTask:
// bool IsInitialized() override {
// return is_initialized_;
// }
//
// void SomeAction() {
// is_initialized_ = true;
// NotifyInitialized();
// }
//
// private:
// bool is_initialized_ = false;
// };
class InitializationTask {
public:
// An interface for an observer of an initialization task.
//
// Sample usage:
//
// class Bar : public InitializationTask::Observer {
// public:
// explicit Bar(Foo* foo) : foo_(foo) {
// if (foo_->IsInitialized()) {
// UseFoo();
// } else {
// foo_->AddInitializationObserver(this);
// }
// }
//
// ~Bar() override {}
//
// // InitializationTask::Observer:
// void OnInitialized(InitializationTask* initialization_task) override {
// initialization_task->RemoveInitializationObserver(this);
// UseFoo();
// }
//
// void UseFoo() {
// foo_->DoSomethingInteresting();
// }
//
// private:
// // Not owned. Must outlive Bar.
// Foo* foo_;
// };
class Observer : public base::CheckedObserver {
public:
~Observer() override;
// Called when the observed task has initialized.
virtual void OnInitialized(InitializationTask* initialization_task) = 0;
};
InitializationTask();
virtual ~InitializationTask();
// Add the |observer| to be notified of initialization.
void AddInitializationObserver(Observer* observer);
// Remove the |observer| of initialization.
void RemoveInitializationObserver(Observer* observer);
// Notify all observers of initialization. Should be called at most once.
void NotifyInitialized();
// Whether the task has initialized.
virtual bool IsInitialized() const = 0;
private:
// The list of observers for this initialization task.
base::ObserverList<Observer> observers_;
// Whether NotifyInitialized() has been called.
bool has_notified_ = false;
DISALLOW_COPY_AND_ASSIGN(InitializationTask);
};
} // namespace payments
#endif // COMPONENTS_PAYMENTS_CONTENT_INITIALIZATION_TASK_H_
...@@ -453,6 +453,10 @@ autofill::AddressNormalizer* PaymentRequestState::GetAddressNormalizer() { ...@@ -453,6 +453,10 @@ autofill::AddressNormalizer* PaymentRequestState::GetAddressNormalizer() {
return payment_request_delegate_->GetAddressNormalizer(); return payment_request_delegate_->GetAddressNormalizer();
} }
bool PaymentRequestState::IsInitialized() const {
return get_all_instruments_finished_;
}
void PaymentRequestState::PopulateProfileCache() { void PaymentRequestState::PopulateProfileCache() {
std::vector<autofill::AutofillProfile*> profiles = std::vector<autofill::AutofillProfile*> profiles =
personal_data_manager_->GetProfilesToSuggest(); personal_data_manager_->GetProfilesToSuggest();
...@@ -556,6 +560,7 @@ void PaymentRequestState::UpdateIsReadyToPayAndNotifyObservers() { ...@@ -556,6 +560,7 @@ void PaymentRequestState::UpdateIsReadyToPayAndNotifyObservers() {
void PaymentRequestState::NotifyOnGetAllPaymentInstrumentsFinished() { void PaymentRequestState::NotifyOnGetAllPaymentInstrumentsFinished() {
for (auto& observer : observers_) for (auto& observer : observers_)
observer.OnGetAllPaymentInstrumentsFinished(); observer.OnGetAllPaymentInstrumentsFinished();
NotifyInitialized();
} }
void PaymentRequestState::NotifyOnSelectedInformationChanged() { void PaymentRequestState::NotifyOnSelectedInformationChanged() {
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "base/macros.h" #include "base/macros.h"
#include "base/observer_list.h" #include "base/observer_list.h"
#include "components/autofill/core/browser/address_normalizer.h" #include "components/autofill/core/browser/address_normalizer.h"
#include "components/payments/content/initialization_task.h"
#include "components/payments/content/payment_request_spec.h" #include "components/payments/content/payment_request_spec.h"
#include "components/payments/content/payment_response_helper.h" #include "components/payments/content/payment_response_helper.h"
#include "components/payments/content/service_worker_payment_app_factory.h" #include "components/payments/content/service_worker_payment_app_factory.h"
...@@ -39,7 +40,8 @@ class ServiceWorkerPaymentInstrument; ...@@ -39,7 +40,8 @@ class ServiceWorkerPaymentInstrument;
// what the merchant has specified, as input into the "is ready to pay" // what the merchant has specified, as input into the "is ready to pay"
// computation. // computation.
class PaymentRequestState : public PaymentResponseHelper::Delegate, class PaymentRequestState : public PaymentResponseHelper::Delegate,
public PaymentRequestSpec::Observer { public PaymentRequestSpec::Observer,
public InitializationTask {
public: public:
// Any class call add itself as Observer via AddObserver() and receive // Any class call add itself as Observer via AddObserver() and receive
// notification about the state changing. // notification about the state changing.
...@@ -219,6 +221,9 @@ class PaymentRequestState : public PaymentResponseHelper::Delegate, ...@@ -219,6 +221,9 @@ class PaymentRequestState : public PaymentResponseHelper::Delegate,
autofill::AddressNormalizer* GetAddressNormalizer(); autofill::AddressNormalizer* GetAddressNormalizer();
// InitializationTask:
bool IsInitialized() const override;
private: private:
// Fetches the Autofill Profiles for this user from the PersonalDataManager, // Fetches the Autofill Profiles for this user from the PersonalDataManager,
// and stores copies of them, owned by this PaymentRequestState, in // and stores copies of them, owned by this PaymentRequestState, in
......
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