Commit ddcd0fc0 authored by Mohamed Amir Yosef's avatar Mohamed Amir Yosef Committed by Commit Bot

[Passwords] Introduce ItemsBubbleController

This CL is one of many refactoring CLs that would split the
ManagePasswordsBubbleModel into different controllers one per view.

Bug: 1044034
Change-Id: Ic4ee0a4bbf79c4a28f2434ebd8dacb1733bc690e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2019265Reviewed-by: default avatarVasilii Sukhanov <vasilii@chromium.org>
Commit-Queue: Mohamed Amir Yosef <mamir@chromium.org>
Cr-Commit-Position: refs/heads/master@{#735397}
parent 6bd2b7db
......@@ -1056,6 +1056,8 @@ jumbo_static_library("ui") {
"passwords/bubble_controllers/auto_sign_in_bubble_controller.h",
"passwords/bubble_controllers/generation_confirmation_bubble_controller.cc",
"passwords/bubble_controllers/generation_confirmation_bubble_controller.h",
"passwords/bubble_controllers/items_bubble_controller.cc",
"passwords/bubble_controllers/items_bubble_controller.h",
"passwords/bubble_controllers/password_bubble_controller_base.cc",
"passwords/bubble_controllers/password_bubble_controller_base.h",
"passwords/credential_leak_dialog_controller.h",
......
// Copyright 2020 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 "chrome/browser/ui/passwords/bubble_controllers/items_bubble_controller.h"
#include "chrome/browser/password_manager/password_store_utils.h"
#include "chrome/browser/ui/passwords/manage_passwords_view_utils.h"
#include "chrome/browser/ui/passwords/passwords_model_delegate.h"
#include "chrome/grit/generated_resources.h"
#include "components/password_manager/core/browser/password_form_metrics_recorder.h"
#include "components/password_manager/core/browser/password_store.h"
#include "content/public/browser/web_contents.h"
#include "ui/base/l10n/l10n_util.h"
namespace metrics_util = password_manager::metrics_util;
namespace {
std::vector<autofill::PasswordForm> DeepCopyForms(
const std::vector<std::unique_ptr<autofill::PasswordForm>>& forms) {
std::vector<autofill::PasswordForm> result;
result.reserve(forms.size());
std::transform(forms.begin(), forms.end(), std::back_inserter(result),
[](const std::unique_ptr<autofill::PasswordForm>& form) {
return *form;
});
return result;
}
} // namespace
ItemsBubbleController::ItemsBubbleController(
base::WeakPtr<PasswordsModelDelegate> delegate)
: PasswordBubbleControllerBase(
std::move(delegate),
/*display_disposition=*/metrics_util::MANUAL_MANAGE_PASSWORDS),
dismissal_reason_(metrics_util::NO_DIRECT_INTERACTION) {
local_credentials_ = DeepCopyForms(delegate_->GetCurrentForms());
GetManagePasswordsDialogTitleText(GetWebContents()->GetVisibleURL(),
delegate_->GetOrigin(),
!local_credentials_.empty(), &title_);
}
ItemsBubbleController::~ItemsBubbleController() {
if (!interaction_reported_)
OnBubbleClosing();
}
void ItemsBubbleController::OnManageClicked(
password_manager::ManagePasswordsReferrer referrer) {
dismissal_reason_ = metrics_util::CLICKED_MANAGE;
if (delegate_)
delegate_->NavigateToPasswordManagerSettingsPage(referrer);
}
void ItemsBubbleController::OnPasswordAction(
const autofill::PasswordForm& password_form,
ManagePasswordsBubbleModel::PasswordAction action) {
Profile* profile = GetProfile();
if (!profile)
return;
password_manager::PasswordStore* password_store =
GetPasswordStore(profile, password_form.IsUsingAccountStore()).get();
DCHECK(password_store);
if (action == ManagePasswordsBubbleModel::REMOVE_PASSWORD)
password_store->RemoveLogin(password_form);
else
password_store->AddLogin(password_form);
}
void ItemsBubbleController::ReportInteractions() {
metrics_util::LogGeneralUIDismissalReason(dismissal_reason_);
// Record UKM statistics on dismissal reason.
if (metrics_recorder_)
metrics_recorder_->RecordUIDismissalReason(dismissal_reason_);
}
base::string16 ItemsBubbleController::GetTitle() const {
return title_;
}
// Copyright 2020 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 CHROME_BROWSER_UI_PASSWORDS_BUBBLE_CONTROLLERS_ITEMS_BUBBLE_CONTROLLER_H_
#define CHROME_BROWSER_UI_PASSWORDS_BUBBLE_CONTROLLERS_ITEMS_BUBBLE_CONTROLLER_H_
#include "chrome/browser/ui/passwords/bubble_controllers/password_bubble_controller_base.h"
#include "base/memory/weak_ptr.h"
#include "chrome/browser/ui/passwords/manage_passwords_bubble_model.h"
#include "components/password_manager/core/browser/manage_passwords_referrer.h"
class PasswordsModelDelegate;
// This controller provides data and actions for the PasswordItemsView.
class ItemsBubbleController : public PasswordBubbleControllerBase {
public:
explicit ItemsBubbleController(
base::WeakPtr<PasswordsModelDelegate> delegate);
~ItemsBubbleController() override;
// Called by the view code when the manage button is clicked by the user.
void OnManageClicked(password_manager::ManagePasswordsReferrer referrer);
// Called by the view code to delete or add a password form to the
// PasswordStore.
void OnPasswordAction(const autofill::PasswordForm& password_form,
ManagePasswordsBubbleModel::PasswordAction action);
// Returns the available credentials which match the current site.
const std::vector<autofill::PasswordForm>& local_credentials() const {
return local_credentials_;
}
private:
// PasswordBubbleControllerBase methods:
base::string16 GetTitle() const override;
void ReportInteractions() override;
std::vector<autofill::PasswordForm> local_credentials_;
base::string16 title_;
// Dismissal reason for a password bubble.
password_manager::metrics_util::UIDismissalReason dismissal_reason_;
};
#endif // CHROME_BROWSER_UI_PASSWORDS_BUBBLE_CONTROLLERS_ITEMS_BUBBLE_CONTROLLER_H_
// Copyright 2020 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 "chrome/browser/ui/passwords/bubble_controllers/items_bubble_controller.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/metrics/histogram_tester.h"
#include "chrome/browser/password_manager/password_store_factory.h"
#include "chrome/browser/ui/passwords/passwords_model_delegate_mock.h"
#include "chrome/test/base/testing_profile.h"
#include "components/password_manager/core/browser/mock_password_store.h"
#include "components/password_manager/core/browser/password_manager_test_utils.h"
#include "content/public/browser/browser_context.h"
#include "content/public/test/browser_task_environment.h"
#include "content/public/test/test_renderer_host.h"
#include "content/public/test/web_contents_tester.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using ::testing::Return;
using ::testing::ReturnRef;
namespace {
constexpr char kUIDismissalReasonGeneralMetric[] =
"PasswordManager.UIDismissalReason";
constexpr char kSiteOrigin[] = "http://example.com/login/";
} // namespace
class ItemsBubbleControllerTest : public ::testing::Test {
public:
ItemsBubbleControllerTest() {
test_web_contents_ =
content::WebContentsTester::CreateTestWebContents(&profile_, nullptr);
mock_delegate_ =
std::make_unique<testing::NiceMock<PasswordsModelDelegateMock>>();
ON_CALL(*mock_delegate_, GetPasswordFormMetricsRecorder())
.WillByDefault(Return(nullptr));
PasswordStoreFactory::GetInstance()->SetTestingFactoryAndUse(
profile(),
base::BindRepeating(
&password_manager::BuildPasswordStore<
content::BrowserContext,
testing::StrictMock<password_manager::MockPasswordStore>>));
}
~ItemsBubbleControllerTest() override = default;
static std::vector<std::unique_ptr<autofill::PasswordForm>> GetCurrentForms();
PasswordsModelDelegateMock* delegate() { return mock_delegate_.get(); }
ItemsBubbleController* controller() { return controller_.get(); }
TestingProfile* profile() { return &profile_; }
password_manager::MockPasswordStore* GetStore() {
return static_cast<password_manager::MockPasswordStore*>(
PasswordStoreFactory::GetInstance()
->GetForProfile(profile(), ServiceAccessType::EXPLICIT_ACCESS)
.get());
}
void Init();
void DestroyController();
private:
content::BrowserTaskEnvironment task_environment_;
content::RenderViewHostTestEnabler rvh_enabler_;
TestingProfile profile_;
std::unique_ptr<content::WebContents> test_web_contents_;
std::unique_ptr<PasswordsModelDelegateMock> mock_delegate_;
std::unique_ptr<ItemsBubbleController> controller_;
};
void ItemsBubbleControllerTest::Init() {
std::vector<std::unique_ptr<autofill::PasswordForm>> forms =
GetCurrentForms();
EXPECT_CALL(*delegate(), GetCurrentForms()).WillOnce(ReturnRef(forms));
GURL origin(kSiteOrigin);
EXPECT_CALL(*delegate(), GetOrigin()).WillOnce(ReturnRef(origin));
EXPECT_CALL(*delegate(), GetWebContents())
.WillRepeatedly(Return(test_web_contents_.get()));
EXPECT_CALL(*delegate(), OnBubbleShown());
controller_.reset(new ItemsBubbleController(mock_delegate_->AsWeakPtr()));
ASSERT_TRUE(testing::Mock::VerifyAndClearExpectations(delegate()));
EXPECT_CALL(*delegate(), GetWebContents())
.WillRepeatedly(Return(test_web_contents_.get()));
}
void ItemsBubbleControllerTest::DestroyController() {
controller_.reset();
}
// static
std::vector<std::unique_ptr<autofill::PasswordForm>>
ItemsBubbleControllerTest::GetCurrentForms() {
autofill::PasswordForm form1;
form1.origin = GURL(kSiteOrigin);
form1.signon_realm = kSiteOrigin;
form1.username_value = base::ASCIIToUTF16("User1");
form1.password_value = base::ASCIIToUTF16("123456");
autofill::PasswordForm form2;
form2.origin = GURL(kSiteOrigin);
form2.signon_realm = kSiteOrigin;
form2.username_value = base::ASCIIToUTF16("User2");
form2.password_value = base::ASCIIToUTF16("654321");
std::vector<std::unique_ptr<autofill::PasswordForm>> forms;
forms.push_back(std::make_unique<autofill::PasswordForm>(form1));
forms.push_back(std::make_unique<autofill::PasswordForm>(form2));
return forms;
}
TEST_F(ItemsBubbleControllerTest, OnManageClicked) {
Init();
EXPECT_CALL(
*delegate(),
NavigateToPasswordManagerSettingsPage(
password_manager::ManagePasswordsReferrer::kManagePasswordsBubble));
controller()->OnManageClicked(
password_manager::ManagePasswordsReferrer::kManagePasswordsBubble);
base::HistogramTester histogram_tester;
DestroyController();
histogram_tester.ExpectUniqueSample(
kUIDismissalReasonGeneralMetric,
password_manager::metrics_util::CLICKED_MANAGE, 1);
}
TEST_F(ItemsBubbleControllerTest, OnPasswordActionAddPassword) {
Init();
autofill::PasswordForm form;
form.origin = GURL(kSiteOrigin);
form.signon_realm = kSiteOrigin;
form.username_value = base::ASCIIToUTF16("User");
form.password_value = base::ASCIIToUTF16("123456");
EXPECT_CALL(*GetStore(), AddLogin(form));
controller()->OnPasswordAction(form,
ManagePasswordsBubbleModel::ADD_PASSWORD);
}
TEST_F(ItemsBubbleControllerTest, OnPasswordActionRemovePassword) {
Init();
autofill::PasswordForm form;
form.origin = GURL(kSiteOrigin);
form.signon_realm = kSiteOrigin;
form.username_value = base::ASCIIToUTF16("User");
form.password_value = base::ASCIIToUTF16("123456");
EXPECT_CALL(*GetStore(), RemoveLogin(form));
controller()->OnPasswordAction(form,
ManagePasswordsBubbleModel::REMOVE_PASSWORD);
}
TEST_F(ItemsBubbleControllerTest, ShouldReturnLocalCredentials) {
Init();
std::vector<autofill::PasswordForm> local_credentials =
controller()->local_credentials();
std::vector<std::unique_ptr<autofill::PasswordForm>>
expected_local_credentials = ItemsBubbleControllerTest::GetCurrentForms();
EXPECT_EQ(local_credentials.size(), expected_local_credentials.size());
for (size_t i = 0; i < local_credentials.size(); i++) {
EXPECT_EQ(local_credentials[i], *expected_local_credentials[i]);
}
}
......@@ -212,9 +212,6 @@ ManagePasswordsBubbleModel::ManagePasswordsBubbleModel(
kCredentialManagementAPI;
UpdatePendingStateTitle();
} else if (state_ == password_manager::ui::MANAGE_STATE) {
local_credentials_ = DeepCopyForms(delegate_->GetCurrentForms());
UpdateManageStateTitle();
}
password_manager::metrics_util::UIDisplayDisposition display_disposition =
......@@ -228,8 +225,6 @@ ManagePasswordsBubbleModel::ManagePasswordsBubbleModel(
display_disposition = metrics_util::MANUAL_WITH_PASSWORD_PENDING_UPDATE;
break;
case password_manager::ui::MANAGE_STATE:
display_disposition = metrics_util::MANUAL_MANAGE_PASSWORDS;
break;
case password_manager::ui::CONFIRMATION_STATE:
case password_manager::ui::CREDENTIAL_REQUEST_STATE:
case password_manager::ui::AUTO_SIGNIN_STATE:
......@@ -318,29 +313,6 @@ void ManagePasswordsBubbleModel::OnSaveClicked() {
}
}
void ManagePasswordsBubbleModel::OnManageClicked(
password_manager::ManagePasswordsReferrer referrer) {
interaction_keeper_->set_dismissal_reason(metrics_util::CLICKED_MANAGE);
if (delegate_)
delegate_->NavigateToPasswordManagerSettingsPage(referrer);
}
void ManagePasswordsBubbleModel::OnPasswordAction(
const autofill::PasswordForm& password_form,
PasswordAction action) {
Profile* profile = GetProfile();
if (!profile)
return;
password_manager::PasswordStore* password_store =
GetPasswordStore(profile, password_form.IsUsingAccountStore()).get();
DCHECK(password_store);
if (action == REMOVE_PASSWORD)
password_store->RemoveLogin(password_form);
else
password_store->AddLogin(password_form);
}
void ManagePasswordsBubbleModel::OnSignInToChromeClicked(
const AccountInfo& account,
bool is_default_promo_account) {
......@@ -457,8 +429,3 @@ void ManagePasswordsBubbleModel::UpdatePendingStateTitle() {
GetSavePasswordDialogTitleTextAndLinkRange(GetWebContents()->GetVisibleURL(),
origin_, type, &title_);
}
void ManagePasswordsBubbleModel::UpdateManageStateTitle() {
GetManagePasswordsDialogTitleText(GetWebContents()->GetVisibleURL(), origin_,
!local_credentials_.empty(), &title_);
}
......@@ -63,14 +63,6 @@ class ManagePasswordsBubbleModel {
// Called by the view code when the save/update button is clicked by the user.
void OnSaveClicked();
// Called by the view code when the manage button is clicked by the user.
void OnManageClicked(password_manager::ManagePasswordsReferrer referrer);
// Called by the view code to delete or add a password form to the
// PasswordStore.
void OnPasswordAction(const autofill::PasswordForm& password_form,
PasswordAction action);
// Called by the view when the "Sign in" button or the "Sync to" button in the
// promo bubble is clicked.
void OnSignInToChromeClicked(const AccountInfo& account,
......@@ -87,10 +79,6 @@ class ManagePasswordsBubbleModel {
const autofill::PasswordForm& pending_password() const {
return pending_password_;
}
// Returns the available credentials which match the current site.
const std::vector<autofill::PasswordForm>& local_credentials() const {
return local_credentials_;
}
bool are_passwords_revealed_when_bubble_is_opened() const {
return are_passwords_revealed_when_bubble_is_opened_;
......@@ -146,8 +134,6 @@ class ManagePasswordsBubbleModel {
class InteractionKeeper;
// Updates |title_| for the PENDING_PASSWORD_STATE.
void UpdatePendingStateTitle();
// Updates |title_| for the MANAGE_STATE.
void UpdateManageStateTitle();
// URL of the page from where this bubble was triggered.
GURL origin_;
......
......@@ -17,7 +17,6 @@
#include "base/test/simple_test_clock.h"
#include "build/build_config.h"
#include "chrome/browser/password_manager/password_store_factory.h"
#include "chrome/browser/sync/profile_sync_service_factory.h"
#include "chrome/browser/ui/passwords/passwords_model_delegate_mock.h"
#include "chrome/test/base/testing_profile.h"
#include "components/password_manager/core/browser/mock_password_store.h"
......@@ -30,7 +29,6 @@
#include "components/password_manager/core/common/password_manager_ui.h"
#include "components/prefs/pref_service.h"
#include "components/signin/public/identity_manager/account_info.h"
#include "components/sync/driver/test_sync_service.h"
#include "components/ukm/test_ukm_recorder.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_task_environment.h"
......@@ -62,13 +60,6 @@ constexpr char kUIDismissalReasonSaveMetric[] =
constexpr char kUIDismissalReasonUpdateMetric[] =
"PasswordManager.UpdateUIDismissalReason";
enum class SyncedTypes { ALL, NONE };
std::unique_ptr<KeyedService> TestingSyncFactoryFunction(
content::BrowserContext* context) {
return std::make_unique<syncer::TestSyncService>();
}
MATCHER_P(AccountEq, expected, "") {
return expected.account_id == arg.account_id && expected.email == arg.email &&
expected.gaia == arg.gaia;
......@@ -131,7 +122,6 @@ class ManagePasswordsBubbleModelTest : public ::testing::Test {
void PretendPasswordWaiting(ManagePasswordsBubbleModel::DisplayReason reason =
ManagePasswordsBubbleModel::AUTOMATIC);
void PretendUpdatePasswordWaiting();
void PretendManagingPasswords();
void DestroyModelAndVerifyControllerExpectations();
void DestroyModelExpectReason(
......@@ -193,14 +183,6 @@ void ManagePasswordsBubbleModelTest::PretendUpdatePasswordWaiting() {
ManagePasswordsBubbleModel::AUTOMATIC);
}
void ManagePasswordsBubbleModelTest::PretendManagingPasswords() {
std::vector<std::unique_ptr<autofill::PasswordForm>> forms =
GetCurrentForms();
EXPECT_CALL(*controller(), GetCurrentForms()).WillOnce(ReturnRef(forms));
SetUpWithState(password_manager::ui::MANAGE_STATE,
ManagePasswordsBubbleModel::USER_ACTION);
}
void ManagePasswordsBubbleModelTest::
DestroyModelAndVerifyControllerExpectations() {
EXPECT_CALL(*controller(), OnBubbleHidden());
......@@ -312,20 +294,6 @@ TEST_F(ManagePasswordsBubbleModelTest, ClickNever) {
DestroyModelExpectReason(password_manager::metrics_util::CLICKED_NEVER);
}
TEST_F(ManagePasswordsBubbleModelTest, ClickManage) {
PretendManagingPasswords();
EXPECT_CALL(
*controller(),
NavigateToPasswordManagerSettingsPage(
password_manager::ManagePasswordsReferrer::kManagePasswordsBubble));
model()->OnManageClicked(
password_manager::ManagePasswordsReferrer::kManagePasswordsBubble);
EXPECT_EQ(password_manager::ui::MANAGE_STATE, model()->state());
DestroyModelExpectReason(password_manager::metrics_util::CLICKED_MANAGE);
}
TEST_F(ManagePasswordsBubbleModelTest, ClickUpdate) {
PretendUpdatePasswordWaiting();
......@@ -460,37 +428,6 @@ TEST_F(ManagePasswordsBubbleModelTest, SignInPromoDismiss) {
}
#endif // !defined(OS_CHROMEOS)
class ManagePasswordsBubbleModelManageLinkTest
: public ManagePasswordsBubbleModelTest,
public ::testing::WithParamInterface<SyncedTypes> {};
TEST_P(ManagePasswordsBubbleModelManageLinkTest, OnManageClicked) {
syncer::TestSyncService* sync_service = static_cast<syncer::TestSyncService*>(
ProfileSyncServiceFactory::GetInstance()->SetTestingFactoryAndUse(
profile(), base::BindRepeating(&TestingSyncFactoryFunction)));
syncer::ModelTypeSet types;
if (GetParam() == SyncedTypes::ALL) {
types = syncer::ModelTypeSet::All();
}
sync_service->SetPreferredDataTypes(types);
sync_service->SetActiveDataTypes(types);
PretendManagingPasswords();
EXPECT_CALL(
*controller(),
NavigateToPasswordManagerSettingsPage(
password_manager::ManagePasswordsReferrer::kManagePasswordsBubble));
model()->OnManageClicked(
password_manager::ManagePasswordsReferrer::kManagePasswordsBubble);
}
INSTANTIATE_TEST_SUITE_P(Default,
ManagePasswordsBubbleModelManageLinkTest,
::testing::Values(SyncedTypes::ALL,
SyncedTypes::NONE));
// Verify that URL keyed metrics are properly recorded.
TEST_F(ManagePasswordsBubbleModelTest, RecordUKMs) {
using BubbleDismissalReason =
......
......@@ -131,7 +131,8 @@ PasswordBubbleViewBase::PasswordBubbleViewBase(
// Create the model only for the states that hasn't been migrated to using the
// bubble controllers.
if (delegate->GetState() != password_manager::ui::AUTO_SIGNIN_STATE &&
delegate->GetState() != password_manager::ui::CONFIRMATION_STATE) {
delegate->GetState() != password_manager::ui::CONFIRMATION_STATE &&
delegate->GetState() != password_manager::ui::MANAGE_STATE) {
model_ = std::make_unique<ManagePasswordsBubbleModel>(
delegate, reason == AUTOMATIC
? ManagePasswordsBubbleModel::AUTOMATIC
......
......@@ -10,8 +10,10 @@
#include "base/macros.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/app/vector_icons/vector_icons.h"
#include "chrome/browser/ui/passwords/bubble_controllers/items_bubble_controller.h"
#include "chrome/browser/ui/passwords/manage_passwords_bubble_model.h"
#include "chrome/browser/ui/passwords/manage_passwords_view_utils.h"
#include "chrome/browser/ui/passwords/passwords_model_delegate.h"
#include "chrome/browser/ui/views/chrome_layout_provider.h"
#include "chrome/browser/ui/views/chrome_typography.h"
#include "chrome/grit/generated_resources.h"
......@@ -245,16 +247,16 @@ PasswordItemsView::PasswordItemsView(content::WebContents* web_contents,
: PasswordBubbleViewBase(web_contents,
anchor_view,
reason,
/*easily_dismissable=*/true) {
/*easily_dismissable=*/true),
controller_(PasswordsModelDelegateFromWebContents(web_contents)) {
DialogDelegate::set_buttons(ui::DIALOG_BUTTON_OK);
DialogDelegate::SetExtraView(CreateManageButton(this));
DCHECK_EQ(password_manager::ui::MANAGE_STATE, model()->state());
if (model()->local_credentials().empty()) {
if (controller_.local_credentials().empty()) {
// A LayoutManager is required for GetHeightForWidth() even without content.
SetLayoutManager(std::make_unique<views::FillLayout>());
} else {
for (auto& password_form : model()->local_credentials()) {
for (auto& password_form : controller_.local_credentials()) {
password_rows_.push_back(
std::make_unique<PasswordRow>(this, &password_form));
}
......@@ -266,18 +268,18 @@ PasswordItemsView::PasswordItemsView(content::WebContents* web_contents,
PasswordItemsView::~PasswordItemsView() = default;
PasswordBubbleControllerBase* PasswordItemsView::GetController() {
return nullptr;
return &controller_;
}
const PasswordBubbleControllerBase* PasswordItemsView::GetController() const {
return nullptr;
return &controller_;
}
void PasswordItemsView::RecreateLayout() {
// This method should only be used when we have password rows, otherwise the
// dialog should only show the no-passwords title and doesn't need to be
// recreated.
DCHECK(!model()->local_credentials().empty());
DCHECK(!controller_.local_credentials().empty());
RemoveAllChildViews(true);
......@@ -307,7 +309,7 @@ void PasswordItemsView::NotifyPasswordFormAction(
RecreateLayout();
// After the view is consistent, notify the model that the password needs to
// be updated (either removed or put back into the store, as appropriate.
model()->OnPasswordAction(password_form, action);
controller_.OnPasswordAction(password_form, action);
}
bool PasswordItemsView::ShouldShowCloseButton() const {
......@@ -323,7 +325,7 @@ gfx::Size PasswordItemsView::CalculatePreferredSize() const {
void PasswordItemsView::ButtonPressed(views::Button* sender,
const ui::Event& event) {
model()->OnManageClicked(
controller_.OnManageClicked(
password_manager::ManagePasswordsReferrer::kManagePasswordsBubble);
CloseBubble();
}
......@@ -9,6 +9,7 @@
#include <vector>
#include "base/macros.h"
#include "chrome/browser/ui/passwords/bubble_controllers/items_bubble_controller.h"
#include "chrome/browser/ui/passwords/manage_passwords_bubble_model.h"
#include "chrome/browser/ui/views/passwords/password_bubble_view_base.h"
#include "components/autofill/core/common/password_form.h"
......@@ -62,6 +63,8 @@ class PasswordItemsView : public PasswordBubbleViewBase,
std::vector<std::unique_ptr<PasswordRow>> password_rows_;
ItemsBubbleController controller_;
DISALLOW_COPY_AND_ASSIGN(PasswordItemsView);
};
......
......@@ -4042,6 +4042,7 @@ test("unit_tests") {
"../browser/ui/page_info/permission_menu_model_unittest.cc",
"../browser/ui/passwords/bubble_controllers/auto_sign_in_bubble_controller_unittest.cc",
"../browser/ui/passwords/bubble_controllers/generation_confirmation_bubble_controller_unittest.cc",
"../browser/ui/passwords/bubble_controllers/items_bubble_controller_unittest.cc",
"../browser/ui/passwords/credential_leak_dialog_controller_impl_unittest.cc",
"../browser/ui/passwords/credential_manager_dialog_controller_impl_unittest.cc",
"../browser/ui/passwords/manage_passwords_bubble_model_unittest.cc",
......
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