Commit 7a1e03d0 authored by Friedrich Horschig's avatar Friedrich Horschig Committed by Commit Bot

[PwdCheckAndroid] Launch edit fragment on button click

This CL introduces opening an edit view as an additional means to change
a compromised password. For that, the coordinator is now able to launch
a fragment (that heavily leans on password_entry_editor.xml).
The fragment itself has no functionality yet and doesn't make use of the
passed credential.

Screenshot in the bug.

Bug: 1114720, 1092444
Change-Id: I0f871600d1c1d1e8c157ffbbeb6edd6f9fd7fbd7
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2353336
Commit-Queue: Friedrich [CET] <fhorschig@chromium.org>
Reviewed-by: default avatarJan Wilken Dörrie <jdoerrie@chromium.org>
Cr-Commit-Position: refs/heads/master@{#798598}
parent 4e7cfcbb
...@@ -47,6 +47,7 @@ android_library("public_java") { ...@@ -47,6 +47,7 @@ android_library("public_java") {
] ]
sources = [ sources = [
"java/src/org/chromium/chrome/browser/password_check/PasswordCheck.java", "java/src/org/chromium/chrome/browser/password_check/PasswordCheck.java",
"java/src/org/chromium/chrome/browser/password_check/PasswordCheckEditFragmentView.java",
"java/src/org/chromium/chrome/browser/password_check/PasswordCheckFragmentView.java", "java/src/org/chromium/chrome/browser/password_check/PasswordCheckFragmentView.java",
"java/src/org/chromium/chrome/browser/password_check/PasswordCheckPreference.java", "java/src/org/chromium/chrome/browser/password_check/PasswordCheckPreference.java",
"java/src/org/chromium/chrome/browser/password_check/PasswordCheckReferrer.java", "java/src/org/chromium/chrome/browser/password_check/PasswordCheckReferrer.java",
...@@ -145,7 +146,9 @@ android_resources("java_resources") { ...@@ -145,7 +146,9 @@ android_resources("java_resources") {
"java/res/drawable-night/password_checkup_warning.xml", "java/res/drawable-night/password_checkup_warning.xml",
"java/res/drawable/password_check_neutral.xml", "java/res/drawable/password_check_neutral.xml",
"java/res/drawable/password_checkup_warning.xml", "java/res/drawable/password_checkup_warning.xml",
"java/res/layout/password_check_edit_fragment.xml",
"java/res/layout/password_check_preference_button.xml", "java/res/layout/password_check_preference_button.xml",
"java/res/menu/password_check_editor_action_bar_menu.xml",
"java/res/values-night/colors.xml", "java/res/values-night/colors.xml",
"java/res/values/colors.xml", "java/res/values/colors.xml",
] ]
......
...@@ -7,6 +7,7 @@ package org.chromium.chrome.browser.password_check; ...@@ -7,6 +7,7 @@ package org.chromium.chrome.browser.password_check;
import android.app.Activity; import android.app.Activity;
import android.content.Intent; import android.content.Intent;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle;
import android.provider.Browser; import android.provider.Browser;
import android.view.MenuItem; import android.view.MenuItem;
...@@ -20,6 +21,8 @@ import org.chromium.chrome.browser.LaunchIntentDispatcher; ...@@ -20,6 +21,8 @@ import org.chromium.chrome.browser.LaunchIntentDispatcher;
import org.chromium.chrome.browser.help.HelpAndFeedback; import org.chromium.chrome.browser.help.HelpAndFeedback;
import org.chromium.chrome.browser.password_check.helper.PasswordCheckReauthenticationHelper; import org.chromium.chrome.browser.password_check.helper.PasswordCheckReauthenticationHelper;
import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.settings.SettingsLauncher;
import org.chromium.chrome.browser.settings.SettingsLauncherImpl;
import org.chromium.ui.modelutil.PropertyModel; import org.chromium.ui.modelutil.PropertyModel;
import org.chromium.ui.modelutil.PropertyModelChangeProcessor; import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
...@@ -175,6 +178,16 @@ class PasswordCheckCoordinator implements PasswordCheckComponentUi, LifecycleObs ...@@ -175,6 +178,16 @@ class PasswordCheckCoordinator implements PasswordCheckComponentUi, LifecycleObs
IntentUtils.safeStartActivity(mFragmentView.getActivity(), intent); IntentUtils.safeStartActivity(mFragmentView.getActivity(), intent);
} }
@Override
public void launchEditPage(CompromisedCredential credential) {
SettingsLauncher launcher = new SettingsLauncherImpl();
Bundle fragmentArgs = new Bundle();
fragmentArgs.putParcelable(
PasswordCheckEditFragmentView.EXTRA_COMPROMISED_CREDENTIAL, credential);
launcher.launchSettingsActivity(
mFragmentView.getContext(), PasswordCheckEditFragmentView.class, fragmentArgs);
}
private Intent getPackageLaunchIntent(String packageName) { private Intent getPackageLaunchIntent(String packageName) {
return Objects.requireNonNull(mFragmentView.getActivity()) return Objects.requireNonNull(mFragmentView.getActivity())
.getPackageManager() .getPackageManager()
......
...@@ -146,11 +146,9 @@ class PasswordCheckMediator ...@@ -146,11 +146,9 @@ class PasswordCheckMediator
return; return;
} }
mReauthenticationHelper.reauthenticate(ReauthReason.EDIT_PASSWORD, mReauthenticationHelper.reauthenticate(ReauthReason.EDIT_PASSWORD, reauthSucceeded -> {
reauthSucceeded if (reauthSucceeded) mChangePasswordDelegate.launchEditPage(credential);
-> { });
// TODO(crbug.com/1114720): Show edit fragment if reauth succeeded.
});
} }
@Override @Override
......
<?xml version="1.0" encoding="utf-8"?>
<!-- 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. -->
<!-- Layout for a preference with a title and a compound drawable above. -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingStart="@dimen/password_entry_editor_content_spacing"
android:paddingEnd="@dimen/password_entry_editor_content_spacing"
android:paddingLeft="@dimen/password_entry_editor_content_spacing"
android:paddingRight="@dimen/password_entry_editor_content_spacing">
<!-- Site -->
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/site_label"
android:labelFor="@+id/site_edit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/password_entry_editor_field_large_top_margin"
android:layout_marginBottom="@dimen/password_entry_editor_field_bottom_margin">
<EditText
tools:ignore="LabelFor"
android:id="@+id/site_edit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:imeOptions="flagNoExtractUi"
android:inputType="text"
android:hint="@string/password_entry_viewer_site_title"
android:enabled="false"/>
</com.google.android.material.textfield.TextInputLayout>
<!-- Username -->
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/username_label"
android:labelFor="@+id/username_edit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/password_entry_editor_field_top_margin"
android:layout_marginBottom="@dimen/password_entry_editor_field_bottom_margin">
<EditText
tools:ignore="LabelFor"
android:id="@+id/username_edit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:imeOptions="flagNoExtractUi"
android:inputType="text"
android:hint="@string/password_entry_viewer_username_title"
android:enabled="false"/>
</com.google.android.material.textfield.TextInputLayout>
<!-- Password -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/password_label"
android:labelFor="@+id/password_edit"
android:layout_height="wrap_content"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_marginTop="@dimen/password_entry_editor_field_top_margin"
android:layout_marginBottom="@dimen/password_entry_editor_field_bottom_margin">
<EditText
tools:ignore="LabelFor"
android:id="@+id/password_edit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:imeOptions="flagNoExtractUi"
android:inputType="textVisiblePassword"
android:hint="@string/password_entry_viewer_password"/>
</com.google.android.material.textfield.TextInputLayout>
<org.chromium.ui.widget.ChromeImageButton
android:id="@+id/password_entry_editor_view_password"
android:background="?attr/selectableItemBackground"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="@drawable/ic_visibility_black"
app:tint="@color/default_icon_color_tint_list"
style="?android:attr/buttonStyleSmall"/>
</LinearLayout>
</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<!-- 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. -->
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" >
<item
android:id="@+id/action_save_edited_password"
android:title="@string/save"
app:showAsAction="always"/>
</menu>
\ No newline at end of file
...@@ -155,8 +155,9 @@ public class CompromisedCredential implements Parcelable { ...@@ -155,8 +155,9 @@ public class CompromisedCredential implements Parcelable {
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(mSignonRealm, mOrigin, mUsername, mDisplayOrigin, mDisplayUsername, return Objects.hash(mSignonRealm, mOrigin.getPossiblyInvalidSpec(), mUsername,
mPassword, mPasswordChangeUrl, mAssociatedApp, mPhished, mHasScript); mDisplayOrigin, mDisplayUsername, mPassword, mPasswordChangeUrl, mAssociatedApp,
mPhished, mHasScript);
} }
@Override @Override
......
...@@ -44,6 +44,12 @@ interface PasswordCheckComponentUi { ...@@ -44,6 +44,12 @@ interface PasswordCheckComponentUi {
* @param credential A {@link CompromisedCredential}. * @param credential A {@link CompromisedCredential}.
*/ */
void launchCctWithScript(CompromisedCredential credential); void launchCctWithScript(CompromisedCredential credential);
/**
* Starts a new site (e.g. a fragment) that allows to change the password saved in Chrome.
* @param credential A {@link CompromisedCredential} to edit in Chrome.
*/
void launchEditPage(CompromisedCredential credential);
} }
/** /**
......
// 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.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.preference.PreferenceFragmentCompat;
/**
* This class is responsible for rendering the edit fragment where users can provide a new password
* for compromised credentials.
* TODO(crbug.com/1092444): Make this a component that is reusable in password settings as well.
*/
public class PasswordCheckEditFragmentView extends PreferenceFragmentCompat {
public static final String EXTRA_COMPROMISED_CREDENTIAL = "extra_compromised_credential";
private static final String EXTRA_NEW_PASSWORD = "extra_new_password";
@Override
public void onCreatePreferences(Bundle bundle, String s) {}
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
setHasOptionsMenu(true);
getActivity().setTitle(R.string.password_entry_viewer_edit_stored_password_action_title);
return inflater.inflate(R.layout.password_check_edit_fragment, container, false);
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
menu.clear(); // Remove help and feedback for this screen.
inflater.inflate(R.menu.password_check_editor_action_bar_menu, menu);
// TODO(crbug.com/1092444): Make the back arrow an 'X'.
}
}
...@@ -12,7 +12,9 @@ import static org.junit.Assert.assertThat; ...@@ -12,7 +12,9 @@ import static org.junit.Assert.assertThat;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.notNull;
import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never; import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
...@@ -278,6 +280,20 @@ public class PasswordCheckControllerTest { ...@@ -278,6 +280,20 @@ public class PasswordCheckControllerTest {
verify(mChangePasswordDelegate).launchCctWithScript(eq(BOB)); verify(mChangePasswordDelegate).launchCctWithScript(eq(BOB));
} }
@Test
public void testOnEditPasswordButtonClick() {
when(mReauthenticationHelper.canReauthenticate()).thenReturn(true);
doAnswer(invocation -> {
Callback<Boolean> cb = invocation.getArgument(1);
cb.onResult(true);
return true;
})
.when(mReauthenticationHelper)
.reauthenticate(anyInt(), notNull());
mMediator.onEdit(ANA);
verify(mChangePasswordDelegate).launchEditPage(eq(ANA));
}
private void assertIdleHeader(MVCListAdapter.ListItem header) { private void assertIdleHeader(MVCListAdapter.ListItem header) {
assertHeaderTypeWithStatus(header, IDLE); assertHeaderTypeWithStatus(header, IDLE);
assertNull(header.model.get(CHECK_PROGRESS)); assertNull(header.model.get(CHECK_PROGRESS));
......
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