Commit 49fa224f authored by Jinho Bang's avatar Jinho Bang Committed by Commit Bot

Reland "PaymentRequest: Fix a memory leak in retry()"

Reason for revert:
A crash occurs because two animations runs in the same time.
In the current implementation, the ViewStack class seems to be able to
run only one animation per one time. So, before one animation finishes,
if another animation runs, it might cause a crash.

The ShowInitialPaymentSheet() doesn't make animation internally but the
GoBackToPaymentSheet() do. So, after retry() calls, if shipping address
or contact editor runs, it might cause a crash because two animations
runs in the same time.

To resolve this issue, this CL adds a parameter to
GoBackToPaymentSheet() to control whether animation runs or not. If the
`animate` parameter is false, just runs without animation. We don't need
to run animation when retry() calls because the payment sheet is already
hidden and the processing spinner is showing.

Original change's description:
> In the current implementation, memory leaks occur becuase the internal
> view_stack_ for payment sheet grows incrementally whenver calling
> retry(). So, this patch uses GoBackToPaymentSheet() instead of
> ShowInitialPaymentSheet() in RetryDialog(). The method has a logic to
> reduce stack's size internally.
>
> Bug: 861704
> Change-Id: I2cb94772485165d1fa96463f16f39edf20ccf7bc
> Reviewed-on: https://chromium-review.googlesource.com/1255082
> Reviewed-by: Rouslan Solomakhin <rouslan@chromium.org>
> Commit-Queue: Jinho Bang <jinho.bang@samsung.com>
> Cr-Commit-Position: refs/heads/master@{#595644}

Bug: 861704
Change-Id: I5ab64423697aa11de97bf68ec9d9f262d7676bb5
Reviewed-on: https://chromium-review.googlesource.com/c/1258813Reviewed-by: default avatarRouslan Solomakhin <rouslan@chromium.org>
Commit-Queue: Jinho Bang <jinho.bang@samsung.com>
Cr-Commit-Position: refs/heads/master@{#596232}
parent d693b570
...@@ -344,7 +344,7 @@ IN_PROC_BROWSER_TEST_F(PaymentRequestContactInfoEditorTest, ...@@ -344,7 +344,7 @@ IN_PROC_BROWSER_TEST_F(PaymentRequestContactInfoEditorTest,
" phone: 'PHONE ERROR'" " phone: 'PHONE ERROR'"
" }" " }"
"}", "}",
DialogEvent::CONTACT_INFO_EDITOR_OPENED); DialogEvent::CONTACT_INFO_EDITOR_OPENED, dialog_view());
EXPECT_EQ(base::ASCIIToUTF16("EMAIL ERROR"), EXPECT_EQ(base::ASCIIToUTF16("EMAIL ERROR"),
GetErrorLabelForType(autofill::EMAIL_ADDRESS)); GetErrorLabelForType(autofill::EMAIL_ADDRESS));
...@@ -381,7 +381,7 @@ IN_PROC_BROWSER_TEST_F( ...@@ -381,7 +381,7 @@ IN_PROC_BROWSER_TEST_F(
" phone: 'PHONE ERROR'" " phone: 'PHONE ERROR'"
" }" " }"
"}", "}",
DialogEvent::CONTACT_INFO_EDITOR_OPENED); DialogEvent::CONTACT_INFO_EDITOR_OPENED, dialog_view());
EXPECT_EQ(base::ASCIIToUTF16("EMAIL ERROR"), EXPECT_EQ(base::ASCIIToUTF16("EMAIL ERROR"),
GetErrorLabelForType(autofill::EMAIL_ADDRESS)); GetErrorLabelForType(autofill::EMAIL_ADDRESS));
...@@ -411,7 +411,8 @@ IN_PROC_BROWSER_TEST_F(PaymentRequestContactInfoEditorTest, ...@@ -411,7 +411,8 @@ IN_PROC_BROWSER_TEST_F(PaymentRequestContactInfoEditorTest,
" name: 'NAME ERROR'," " name: 'NAME ERROR',"
" phone: 'PHONE ERROR'" " phone: 'PHONE ERROR'"
" }" " }"
"}"); "}",
dialog_view());
const int kErrorLabelOffset = const int kErrorLabelOffset =
static_cast<int>(DialogViewID::ERROR_LABEL_OFFSET); static_cast<int>(DialogViewID::ERROR_LABEL_OFFSET);
......
...@@ -638,10 +638,13 @@ void PaymentRequestBrowserTestBase::PayWithCreditCard( ...@@ -638,10 +638,13 @@ void PaymentRequestBrowserTestBase::PayWithCreditCard(
} }
void PaymentRequestBrowserTestBase::RetryPaymentRequest( void PaymentRequestBrowserTestBase::RetryPaymentRequest(
const std::string& validation_errors) { const std::string& validation_errors,
ResetEventWaiterForSequence( PaymentRequestDialogView* dialog_view) {
{DialogEvent::PROCESSING_SPINNER_HIDDEN, DialogEvent::SPEC_DONE_UPDATING, EXPECT_EQ(2U, dialog_view->view_stack_for_testing()->size());
DialogEvent::PROCESSING_SPINNER_HIDDEN, DialogEvent::DIALOG_OPENED}); ResetEventWaiterForSequence({DialogEvent::PROCESSING_SPINNER_HIDDEN,
DialogEvent::SPEC_DONE_UPDATING,
DialogEvent::PROCESSING_SPINNER_HIDDEN,
DialogEvent::BACK_TO_PAYMENT_SHEET_NAVIGATION});
ASSERT_TRUE(content::ExecuteScript(GetActiveWebContents(), ASSERT_TRUE(content::ExecuteScript(GetActiveWebContents(),
"retry(" + validation_errors + ");")); "retry(" + validation_errors + ");"));
...@@ -651,11 +654,13 @@ void PaymentRequestBrowserTestBase::RetryPaymentRequest( ...@@ -651,11 +654,13 @@ void PaymentRequestBrowserTestBase::RetryPaymentRequest(
void PaymentRequestBrowserTestBase::RetryPaymentRequest( void PaymentRequestBrowserTestBase::RetryPaymentRequest(
const std::string& validation_errors, const std::string& validation_errors,
const DialogEvent& dialog_event) { const DialogEvent& dialog_event,
PaymentRequestDialogView* dialog_view) {
EXPECT_EQ(2U, dialog_view->view_stack_for_testing()->size());
ResetEventWaiterForSequence( ResetEventWaiterForSequence(
{DialogEvent::PROCESSING_SPINNER_HIDDEN, DialogEvent::SPEC_DONE_UPDATING, {DialogEvent::PROCESSING_SPINNER_HIDDEN, DialogEvent::SPEC_DONE_UPDATING,
DialogEvent::PROCESSING_SPINNER_HIDDEN, DialogEvent::DIALOG_OPENED, DialogEvent::PROCESSING_SPINNER_HIDDEN,
dialog_event}); DialogEvent::BACK_TO_PAYMENT_SHEET_NAVIGATION, dialog_event});
ASSERT_TRUE(content::ExecuteScript(GetActiveWebContents(), ASSERT_TRUE(content::ExecuteScript(GetActiveWebContents(),
"retry(" + validation_errors + ");")); "retry(" + validation_errors + ");"));
......
...@@ -209,9 +209,11 @@ class PaymentRequestBrowserTestBase ...@@ -209,9 +209,11 @@ class PaymentRequestBrowserTestBase
void PayWithCreditCardAndWait(const base::string16& cvc, void PayWithCreditCardAndWait(const base::string16& cvc,
PaymentRequestDialogView* dialog_view); PaymentRequestDialogView* dialog_view);
void PayWithCreditCard(const base::string16& cvc); void PayWithCreditCard(const base::string16& cvc);
void RetryPaymentRequest(const std::string& validation_errors);
void RetryPaymentRequest(const std::string& validation_errors, void RetryPaymentRequest(const std::string& validation_errors,
const DialogEvent& dialog_event); PaymentRequestDialogView* dialog_view);
void RetryPaymentRequest(const std::string& validation_errors,
const DialogEvent& dialog_event,
PaymentRequestDialogView* dialog_view);
// Getting/setting the |value| in the textfield of a given |type|. // Getting/setting the |value| in the textfield of a given |type|.
base::string16 GetEditorTextfieldValue(autofill::ServerFieldType type); base::string16 GetEditorTextfieldValue(autofill::ServerFieldType type);
......
...@@ -189,7 +189,7 @@ void PaymentRequestDialogView::ShowPaymentHandlerScreen( ...@@ -189,7 +189,7 @@ void PaymentRequestDialogView::ShowPaymentHandlerScreen(
void PaymentRequestDialogView::RetryDialog() { void PaymentRequestDialogView::RetryDialog() {
HideProcessingSpinner(); HideProcessingSpinner();
ShowInitialPaymentSheet(); GoBackToPaymentSheet(false /* animate */);
if (request_->spec()->has_shipping_address_error()) { if (request_->spec()->has_shipping_address_error()) {
autofill::AutofillProfile* profile = autofill::AutofillProfile* profile =
...@@ -265,11 +265,11 @@ void PaymentRequestDialogView::GoBack() { ...@@ -265,11 +265,11 @@ void PaymentRequestDialogView::GoBack() {
observer_for_testing_->OnBackNavigation(); observer_for_testing_->OnBackNavigation();
} }
void PaymentRequestDialogView::GoBackToPaymentSheet() { void PaymentRequestDialogView::GoBackToPaymentSheet(bool animate) {
// This assumes that the Payment Sheet is the first view in the stack. Thus if // This assumes that the Payment Sheet is the first view in the stack. Thus if
// there is only one view, we are already showing the payment sheet. // there is only one view, we are already showing the payment sheet.
if (view_stack_->size() > 1) if (view_stack_->size() > 1)
view_stack_->PopMany(view_stack_->size() - 1); view_stack_->PopMany(view_stack_->size() - 1, animate);
if (observer_for_testing_) if (observer_for_testing_)
observer_for_testing_->OnBackToPaymentSheetNavigation(); observer_for_testing_->OnBackToPaymentSheetNavigation();
......
...@@ -125,7 +125,7 @@ class PaymentRequestDialogView : public views::DialogDelegateView, ...@@ -125,7 +125,7 @@ class PaymentRequestDialogView : public views::DialogDelegateView,
void Pay(); void Pay();
void GoBack(); void GoBack();
void GoBackToPaymentSheet(); void GoBackToPaymentSheet(bool animate = true);
void ShowContactProfileSheet(); void ShowContactProfileSheet();
void ShowOrderSummary(); void ShowOrderSummary();
void ShowShippingProfileSheet(); void ShowShippingProfileSheet();
......
...@@ -1286,7 +1286,7 @@ IN_PROC_BROWSER_TEST_F(PaymentRequestShippingAddressEditorTest, ...@@ -1286,7 +1286,7 @@ IN_PROC_BROWSER_TEST_F(PaymentRequestShippingAddressEditorTest,
" city: 'CITY ERROR'" " city: 'CITY ERROR'"
" }" " }"
"}", "}",
DialogEvent::SHIPPING_ADDRESS_EDITOR_OPENED); DialogEvent::SHIPPING_ADDRESS_EDITOR_OPENED, dialog_view());
EXPECT_EQ(base::ASCIIToUTF16("ADDRESS LINE ERROR"), EXPECT_EQ(base::ASCIIToUTF16("ADDRESS LINE ERROR"),
GetErrorLabelForType(autofill::ADDRESS_HOME_STREET_ADDRESS)); GetErrorLabelForType(autofill::ADDRESS_HOME_STREET_ADDRESS));
...@@ -1322,7 +1322,7 @@ IN_PROC_BROWSER_TEST_F( ...@@ -1322,7 +1322,7 @@ IN_PROC_BROWSER_TEST_F(
" city: 'CITY ERROR'" " city: 'CITY ERROR'"
" }" " }"
"}", "}",
DialogEvent::SHIPPING_ADDRESS_EDITOR_OPENED); DialogEvent::SHIPPING_ADDRESS_EDITOR_OPENED, dialog_view());
EXPECT_EQ(base::ASCIIToUTF16("ADDRESS LINE ERROR"), EXPECT_EQ(base::ASCIIToUTF16("ADDRESS LINE ERROR"),
GetErrorLabelForType(autofill::ADDRESS_HOME_STREET_ADDRESS)); GetErrorLabelForType(autofill::ADDRESS_HOME_STREET_ADDRESS));
...@@ -1349,7 +1349,8 @@ IN_PROC_BROWSER_TEST_F(PaymentRequestShippingAddressEditorTest, ...@@ -1349,7 +1349,8 @@ IN_PROC_BROWSER_TEST_F(PaymentRequestShippingAddressEditorTest,
" addressLine: 'ADDRESS LINE ERROR'," " addressLine: 'ADDRESS LINE ERROR',"
" city: 'CITY ERROR'" " city: 'CITY ERROR'"
" }" " }"
"}"); "}",
dialog_view());
const int kErrorLabelOffset = const int kErrorLabelOffset =
static_cast<int>(DialogViewID::ERROR_LABEL_OFFSET); static_cast<int>(DialogViewID::ERROR_LABEL_OFFSET);
......
...@@ -60,21 +60,23 @@ void ViewStack::Push(std::unique_ptr<views::View> view, bool animate) { ...@@ -60,21 +60,23 @@ void ViewStack::Push(std::unique_ptr<views::View> view, bool animate) {
} }
} }
void ViewStack::Pop() { void ViewStack::Pop(bool animate) {
DCHECK_LT(1u, size()); // There must be at least one view left after popping. DCHECK_LT(1u, size()); // There must be at least one view left after popping.
gfx::Rect destination = bounds();
destination.set_origin(gfx::Point(width(), 0));
// Set the second-to-last view as visible, since it is about to be revealed // Set the second-to-last view as visible, since it is about to be revealed
// when the last view animates out. // when the last view animates out.
stack_[size() - 2]->SetVisible(true); stack_[size() - 2]->SetVisible(true);
slide_out_animator_->AnimateViewTo( if (animate) {
stack_.back().get(), destination); gfx::Rect destination = bounds();
destination.set_origin(gfx::Point(width(), 0));
slide_out_animator_->AnimateViewTo(stack_.back().get(), destination);
} else {
stack_.pop_back();
}
} }
void ViewStack::PopMany(int n) { void ViewStack::PopMany(int n, bool animate) {
DCHECK_LT(static_cast<size_t>(n), size()); // The stack can never be empty. DCHECK_LT(static_cast<size_t>(n), size()); // The stack can never be empty.
size_t pre_size = stack_.size(); size_t pre_size = stack_.size();
...@@ -83,7 +85,7 @@ void ViewStack::PopMany(int n) { ...@@ -83,7 +85,7 @@ void ViewStack::PopMany(int n) {
stack_.erase(stack_.end() - n, stack_.end() - 1); stack_.erase(stack_.end() - n, stack_.end() - 1);
DCHECK_EQ(pre_size - n + 1, stack_.size()); DCHECK_EQ(pre_size - n + 1, stack_.size());
Pop(); Pop(animate);
} }
size_t ViewStack::size() const { size_t ViewStack::size() const {
......
...@@ -33,11 +33,15 @@ class ViewStack : public views::BoundsAnimatorObserver, ...@@ -33,11 +33,15 @@ class ViewStack : public views::BoundsAnimatorObserver,
// Removes a view from the stack, animates it out of view, and makes sure // Removes a view from the stack, animates it out of view, and makes sure
// it's properly deleted after the animation. // it's properly deleted after the animation.
void Pop(); // If |animate| is false, the view will simply be gone to the hierarchy
// without the sliding animation.
void Pop(bool animate = true);
// Removes |n| views from the stack but only animates the topmost one. The end // Removes |n| views from the stack but only animates the topmost one. The end
// result is an animation from the top-most view to the destination view. // result is an animation from the top-most view to the destination view.
void PopMany(int n); // If |animate| is false, the view will simply be gone to the hierarchy
// without the sliding animation.
void PopMany(int n, bool animate = true);
size_t size() const; size_t size() const;
......
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