blob: 50cc2d2baa001a96a5ff8686786019986cbe5b62 [file] [log] [blame]
// 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.
package org.chromium.chrome.browser.password_check;
import android.view.MenuItem;
import androidx.annotation.VisibleForTesting;
import androidx.lifecycle.LifecycleObserver;
import org.chromium.chrome.browser.feedback.HelpAndFeedbackLauncher;
import org.chromium.chrome.browser.password_check.helper.PasswordCheckChangePasswordHelper;
import org.chromium.chrome.browser.password_check.helper.PasswordCheckIconHelper;
import org.chromium.chrome.browser.password_check.helper.PasswordCheckReauthenticationHelper;
import org.chromium.chrome.browser.password_check.internal.R;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.components.browser_ui.settings.SettingsLauncher;
import org.chromium.components.favicon.LargeIconBridge;
import org.chromium.ui.modelutil.PropertyModel;
import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
/**
* Creates the PasswordCheckComponentUi. This class is responsible for managing the UI for the check
* of the leaked password.
*/
class PasswordCheckCoordinator implements PasswordCheckComponentUi, LifecycleObserver {
private HelpAndFeedbackLauncher mHelpAndFeedbackLauncher;
private final PasswordCheckFragmentView mFragmentView;
private final SettingsLauncher mSettingsLauncher;
private final PasswordCheckReauthenticationHelper mReauthenticationHelper;
private final PasswordCheckMediator mMediator;
private PropertyModel mModel;
/**
* Blueprint for a class that handles interactions with credentials.
*/
interface CredentialEventHandler {
/**
* Edits the given Credential in the password store.
* @param credential A {@link CompromisedCredential} to be edited.
*/
void onEdit(CompromisedCredential credential);
/**
* Removes the given Credential from the password store.
* @param credential A {@link CompromisedCredential} to be removed.
*/
void onRemove(CompromisedCredential credential);
/**
* View the given Credential.
* @param credential A {@link CompromisedCredential} to be viewed.
*/
void onView(CompromisedCredential credential);
/**
* Opens a password change form or home page of |credential|'s origin or an app.
* @param credential A {@link CompromisedCredential} to be changed.
*/
void onChangePasswordButtonClick(CompromisedCredential credential);
/**
* Starts a script to change a {@link CompromisedCredential}. Can be called only if {@link
* CompromisedCredential#hasScript()}.
* @param credential A {@link CompromisedCredential} to be change with a script.
*/
void onChangePasswordWithScriptButtonClick(CompromisedCredential credential);
}
PasswordCheckCoordinator(PasswordCheckFragmentView fragmentView,
HelpAndFeedbackLauncher helpAndFeedbackLauncher, SettingsLauncher settingsLauncher,
PasswordCheckComponentUi.CustomTabIntentHelper customTabIntentHelper,
PasswordCheckComponentUi.TrustedIntentHelper trustedIntentHelper) {
mHelpAndFeedbackLauncher = helpAndFeedbackLauncher;
mFragmentView = fragmentView;
mSettingsLauncher = settingsLauncher;
// TODO(crbug.com/1101256): If help is part of the view, make mediator the delegate.
mFragmentView.setComponentDelegate(this);
// TODO(crbug.com/1092444): Ideally, the following replaces the lifecycle event forwarding.
// Figure out why it isn't working and use the following lifecycle observer once it does:
// mFragmentView.getLifecycle().addObserver(this);
mReauthenticationHelper = new PasswordCheckReauthenticationHelper(
mFragmentView.getActivity(), mFragmentView.getParentFragmentManager());
PasswordCheckChangePasswordHelper changePasswordHelper =
new PasswordCheckChangePasswordHelper(mFragmentView.getActivity(),
mSettingsLauncher, customTabIntentHelper, trustedIntentHelper);
PasswordCheckIconHelper iconHelper = new PasswordCheckIconHelper(
new LargeIconBridge(Profile.getLastUsedRegularProfile()),
mFragmentView.getResources().getDimensionPixelSize(
org.chromium.chrome.browser.ui.favicon.R.dimen.default_favicon_size));
mMediator = new PasswordCheckMediator(
changePasswordHelper, mReauthenticationHelper, mSettingsLauncher, iconHelper);
}
private void launchCheckupInAccount() {
PasswordCheckFactory.getOrCreate(mSettingsLauncher)
.launchCheckupInAccount(mFragmentView.getActivity());
}
@Override
public void onStartFragment() {
// In the rare case of a restarted activity, don't recreate the model and mediator.
if (mModel == null) {
mModel = PasswordCheckProperties.createDefaultModel();
PasswordCheckCoordinator.setUpModelChangeProcessors(mModel, mFragmentView);
mMediator.initialize(mModel, PasswordCheckFactory.getOrCreate(mSettingsLauncher),
mFragmentView.getReferrer(), this::launchCheckupInAccount);
}
}
@Override
public void onResumeFragment() {
mMediator.onResumeFragment();
mReauthenticationHelper.onReauthenticationMaybeHappened();
}
@Override
public void onDestroyFragment() {
mMediator.stopCheck();
if (mFragmentView.getActivity() == null || mFragmentView.getActivity().isFinishing()) {
mMediator
.onUserLeavesCheckPage(); // Should be called only if the activity is finishing.
mMediator.destroy();
mModel = null;
}
}
// TODO(crbug.com/1101256): Move to view code.
@Override
public boolean handleHelp(MenuItem item) {
if (item.getItemId() == R.id.menu_id_targeted_help) {
mHelpAndFeedbackLauncher.show(mFragmentView.getActivity(),
mFragmentView.getActivity().getString(R.string.help_context_check_passwords),
Profile.getLastUsedRegularProfile(), null);
return true;
}
return false;
}
@Override
public void destroy() {
PasswordCheckFactory.destroy();
}
/**
* Connects the given model with the given view using Model Change Processors.
* @param model A {@link PropertyModel} built with {@link PasswordCheckProperties}.
* @param view A {@link PasswordCheckFragmentView}.
*/
@VisibleForTesting
static void setUpModelChangeProcessors(PropertyModel model, PasswordCheckFragmentView view) {
PropertyModelChangeProcessor.create(
model, view, PasswordCheckViewBinder::bindPasswordCheckView);
}
}