Commit b27232d7 authored by Eleonora Rocchi's avatar Eleonora Rocchi Committed by Commit Bot

[PwdCheckAndroid] Add redirect to Google Password Check on quota limit

This CL adds the logic to redirect the user to the Google Password
Check on quota limit error. The redirect is called through
PasswordCheckBridge to avoid dependencies on chrome_java.

IDS_PASSWORD_CHECK_STATUS_MESSAGE_ERROR_QUOTA_LIMIT_ACCOUNT_CHECK.png
https://storage.cloud.google.com/chromium-translation-screenshots/c4546cf199aa6314ead807fa1fc0e1ed8b779a83

Bug: 1092444
Change-Id: I374ad088c305d299fea00f412f27dd6ab3d0e9b5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2362023Reviewed-by: default avatarIoana Pandele <ioanap@chromium.org>
Reviewed-by: default avatarFriedrich [CET] <fhorschig@chromium.org>
Commit-Queue: Eleonora Rocchi <erocchi@google.com>
Cr-Commit-Position: refs/heads/master@{#799117}
parent 83874a6f
......@@ -3,6 +3,7 @@
// found in the LICENSE file.
package org.chromium.chrome.browser.password_manager;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
......@@ -19,13 +20,11 @@ import org.chromium.ui.base.WindowAndroid;
*/
public class PasswordCheckupLauncher {
@CalledByNative
private static void launchCheckupInAccount(String checkupUrl, WindowAndroid windowAndroid) {
private static void launchCheckupInAccountWithWindowAndroid(
String checkupUrl, WindowAndroid windowAndroid) {
if (windowAndroid.getContext().get() == null) return; // Window not available yet/anymore.
ChromeActivity activity = (ChromeActivity) windowAndroid.getActivity().get();
if (tryLaunchingNativePasswordCheckup(activity)) return;
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(checkupUrl));
intent.setPackage(activity.getPackageName());
activity.startActivity(intent);
launchCheckupInAccountWithActivity(checkupUrl, activity);
}
@CalledByNative
......@@ -36,7 +35,15 @@ public class PasswordCheckupLauncher {
windowAndroid.getContext().get(), PasswordCheckReferrer.LEAK_DIALOG);
}
private static boolean tryLaunchingNativePasswordCheckup(ChromeActivity activity) {
@CalledByNative
private static void launchCheckupInAccountWithActivity(String checkupUrl, Activity activity) {
if (tryLaunchingNativePasswordCheckup(activity)) return;
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(checkupUrl));
intent.setPackage(activity.getPackageName());
activity.startActivity(intent);
}
private static boolean tryLaunchingNativePasswordCheckup(Activity activity) {
GooglePasswordManagerUIProvider googlePasswordManagerUIProvider =
AppHooks.get().createGooglePasswordManagerUIProvider();
if (googlePasswordManagerUIProvider == null) return false;
......
......@@ -2845,6 +2845,8 @@ static_library("browser") {
"password_manager/android/password_accessory_controller_impl.cc",
"password_manager/android/password_accessory_controller_impl.h",
"password_manager/android/password_accessory_metrics_util.h",
"password_manager/android/password_checkup_launcher_helper.cc",
"password_manager/android/password_checkup_launcher_helper.h",
"password_manager/android/password_generation_controller.h",
"password_manager/android/password_generation_controller_impl.cc",
"password_manager/android/password_generation_controller_impl.h",
......
......@@ -4,6 +4,8 @@
package org.chromium.chrome.browser.password_check;
import android.app.Activity;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.NativeMethods;
import org.chromium.url.GURL;
......@@ -136,6 +138,13 @@ class PasswordCheckBridge {
mNativePasswordCheckBridge, credentials);
}
/**
* Launch the password check in the Google Account.
*/
void launchCheckupInAccount(Activity activity) {
PasswordCheckBridgeJni.get().launchCheckupInAccount(mNativePasswordCheckBridge, activity);
}
void updateCredential(CompromisedCredential credential, String newPassword) {
PasswordCheckBridgeJni.get().updateCredential(
mNativePasswordCheckBridge, credential, newPassword);
......@@ -168,6 +177,7 @@ class PasswordCheckBridge {
int getSavedPasswordsCount(long nativePasswordCheckBridge);
void getCompromisedCredentials(
long nativePasswordCheckBridge, CompromisedCredential[] credentials);
void launchCheckupInAccount(long nativePasswordCheckBridge, Activity activity);
void updateCredential(long nativePasswordCheckBridge, CompromisedCredential credential,
String newPassword);
void removeCredential(long nativePasswordCheckBridge, CompromisedCredential credentials);
......
......@@ -73,14 +73,18 @@ class PasswordCheckCoordinator implements PasswordCheckComponentUi, LifecycleObs
mReauthenticationHelper);
}
private void launchCheckupInAccount() {
PasswordCheckFactory.getOrCreate().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(), mFragmentView.getReferrer());
mMediator.initialize(mModel, PasswordCheckFactory.getOrCreate(),
mFragmentView.getReferrer(), this::launchCheckupInAccount);
}
}
......
......@@ -4,6 +4,7 @@
package org.chromium.chrome.browser.password_check;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
......@@ -127,6 +128,11 @@ class PasswordCheckImpl implements PasswordCheck, PasswordCheckObserver {
return mPasswordCheckBridge.getSavedPasswordsCount();
}
@Override
public void launchCheckupInAccount(Activity activity) {
mPasswordCheckBridge.launchCheckupInAccount(activity);
}
@Override
public void startCheck() {
mPasswordCheckBridge.startCheck();
......
......@@ -13,6 +13,7 @@ import static org.chromium.chrome.browser.password_check.PasswordCheckProperties
import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.HeaderProperties.CHECK_STATUS;
import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.HeaderProperties.CHECK_TIMESTAMP;
import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.HeaderProperties.COMPROMISED_CREDENTIALS_COUNT;
import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.HeaderProperties.LAUNCH_ACCOUNT_CHECKUP_ACTION;
import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.HeaderProperties.RESTART_BUTTON_ACTION;
import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.HeaderProperties.UNKNOWN_PROGRESS;
import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.ITEMS;
......@@ -39,6 +40,7 @@ class PasswordCheckMediator
private final PasswordCheckChangePasswordHelper mChangePasswordDelegate;
private PropertyModel mModel;
private PasswordCheckComponentUi.Delegate mDelegate;
private Runnable mLaunchCheckupInAccount;
PasswordCheckMediator(PasswordCheckChangePasswordHelper changePasswordDelegate,
PasswordCheckReauthenticationHelper reauthenticationHelper) {
......@@ -47,9 +49,10 @@ class PasswordCheckMediator
}
void initialize(PropertyModel model, PasswordCheckComponentUi.Delegate delegate,
@PasswordCheckReferrer int passwordCheckReferrer) {
@PasswordCheckReferrer int passwordCheckReferrer, Runnable launchCheckupInAccount) {
mModel = model;
mDelegate = delegate;
mLaunchCheckupInAccount = launchCheckupInAccount;
// If a run is scheduled to happen soon, initialize the UI as running to prevent flickering.
// Otherwise, initialize the UI with last known state (defaults to IDLE before first run).
......@@ -73,6 +76,7 @@ class PasswordCheckMediator
items.add(new ListItem(PasswordCheckProperties.ItemType.HEADER,
new PropertyModel.Builder(PasswordCheckProperties.HeaderProperties.ALL_KEYS)
.with(CHECK_STATUS, PasswordCheckUIStatus.RUNNING)
.with(LAUNCH_ACCOUNT_CHECKUP_ACTION, mLaunchCheckupInAccount)
.with(RESTART_BUTTON_ACTION, this::runCheck)
.build()));
}
......@@ -96,6 +100,7 @@ class PasswordCheckMediator
.with(CHECK_STATUS, PasswordCheckUIStatus.RUNNING)
.with(CHECK_TIMESTAMP, null)
.with(COMPROMISED_CREDENTIALS_COUNT, null)
.with(LAUNCH_ACCOUNT_CHECKUP_ACTION, mLaunchCheckupInAccount)
.with(RESTART_BUTTON_ACTION, this::runCheck)
.build();
} else {
......
......@@ -67,11 +67,15 @@ class PasswordCheckProperties {
static final PropertyModel
.WritableObjectPropertyKey<Integer> COMPROMISED_CREDENTIALS_COUNT =
new PropertyModel.WritableObjectPropertyKey<>("compromised_credentials_count");
static final PropertyModel
.ReadableObjectPropertyKey<Runnable> LAUNCH_ACCOUNT_CHECKUP_ACTION =
new PropertyModel.ReadableObjectPropertyKey<>("launch_account_checkup_action");
static final PropertyModel.ReadableObjectPropertyKey<Runnable> RESTART_BUTTON_ACTION =
new PropertyModel.WritableObjectPropertyKey<>("restart_button_action");
new PropertyModel.ReadableObjectPropertyKey<>("restart_button_action");
static final PropertyKey[] ALL_KEYS = {CHECK_PROGRESS, CHECK_STATUS, CHECK_TIMESTAMP,
COMPROMISED_CREDENTIALS_COUNT, RESTART_BUTTON_ACTION};
COMPROMISED_CREDENTIALS_COUNT, LAUNCH_ACCOUNT_CHECKUP_ACTION,
RESTART_BUTTON_ACTION};
static final Pair<Integer, Integer> UNKNOWN_PROGRESS = new Pair<>(-1, -1);
......
......@@ -13,6 +13,7 @@ import static org.chromium.chrome.browser.password_check.PasswordCheckProperties
import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.HeaderProperties.CHECK_STATUS;
import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.HeaderProperties.CHECK_TIMESTAMP;
import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.HeaderProperties.COMPROMISED_CREDENTIALS_COUNT;
import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.HeaderProperties.LAUNCH_ACCOUNT_CHECKUP_ACTION;
import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.HeaderProperties.RESTART_BUTTON_ACTION;
import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.HeaderProperties.UNKNOWN_PROGRESS;
import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.ITEMS;
......@@ -20,6 +21,7 @@ import static org.chromium.chrome.browser.password_check.PasswordCheckProperties
import android.content.Context;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.text.method.LinkMovementMethod;
import android.util.Pair;
import android.view.View;
import android.view.ViewGroup;
......@@ -44,6 +46,8 @@ import org.chromium.ui.modelutil.PropertyKey;
import org.chromium.ui.modelutil.PropertyModel;
import org.chromium.ui.modelutil.RecyclerViewAdapter;
import org.chromium.ui.modelutil.SimpleRecyclerViewMcp;
import org.chromium.ui.text.NoUnderlineClickableSpan;
import org.chromium.ui.text.SpanApplier;
import org.chromium.ui.widget.ButtonCompat;
/**
......@@ -186,22 +190,30 @@ class PasswordCheckViewBinder {
int status = model.get(CHECK_STATUS);
Long checkTimestamp = model.get(CHECK_TIMESTAMP);
Integer compromisedCredentialsCount = model.get(COMPROMISED_CREDENTIALS_COUNT);
Runnable launchCheckupInAccount = model.get(LAUNCH_ACCOUNT_CHECKUP_ACTION);
if (key == CHECK_PROGRESS) {
updateStatusText(view, status, compromisedCredentialsCount, checkTimestamp, progress);
updateStatusText(view, status, compromisedCredentialsCount, checkTimestamp, progress,
launchCheckupInAccount);
} else if (key == CHECK_STATUS) {
updateActionButton(view, status, model.get(RESTART_BUTTON_ACTION));
updateStatusIcon(view, status, compromisedCredentialsCount);
updateStatusIllustration(view, status, compromisedCredentialsCount);
updateStatusText(view, status, compromisedCredentialsCount, checkTimestamp, progress);
updateStatusText(view, status, compromisedCredentialsCount, checkTimestamp, progress,
launchCheckupInAccount);
updateStatusSubtitle(view, status, compromisedCredentialsCount);
} else if (key == CHECK_TIMESTAMP) {
updateStatusText(view, status, compromisedCredentialsCount, checkTimestamp, progress);
updateStatusText(view, status, compromisedCredentialsCount, checkTimestamp, progress,
launchCheckupInAccount);
} else if (key == COMPROMISED_CREDENTIALS_COUNT) {
updateStatusIcon(view, status, compromisedCredentialsCount);
updateStatusIllustration(view, status, compromisedCredentialsCount);
updateStatusText(view, status, compromisedCredentialsCount, checkTimestamp, progress);
updateStatusText(view, status, compromisedCredentialsCount, checkTimestamp, progress,
launchCheckupInAccount);
updateStatusSubtitle(view, status, compromisedCredentialsCount);
} else if (key == LAUNCH_ACCOUNT_CHECKUP_ACTION) {
assert model.get(LAUNCH_ACCOUNT_CHECKUP_ACTION)
!= null : "Launch checkup in account is always required.";
} else if (key == RESTART_BUTTON_ACTION) {
assert model.get(RESTART_BUTTON_ACTION) != null : "Restart action is always required.";
} else {
......@@ -268,7 +280,7 @@ class PasswordCheckViewBinder {
private static void updateStatusText(View view, @PasswordCheckUIStatus int status,
Integer compromisedCredentialsCount, Long checkTimestamp,
Pair<Integer, Integer> progress) {
Pair<Integer, Integer> progress, Runnable launchCheckupInAccount) {
// TODO(crbug.com/1114051): Set default values for header properties.
if (status == PasswordCheckUIStatus.IDLE
&& (compromisedCredentialsCount == null || checkTimestamp == null)) {
......@@ -277,8 +289,9 @@ class PasswordCheckViewBinder {
if (status == PasswordCheckUIStatus.RUNNING && progress == null) return;
TextView statusMessage = view.findViewById(R.id.check_status_message);
statusMessage.setText(
getStatusMessage(view, status, compromisedCredentialsCount, progress));
statusMessage.setText(getStatusMessage(
view, status, compromisedCredentialsCount, progress, launchCheckupInAccount));
statusMessage.setMovementMethod(LinkMovementMethod.getInstance());
LinearLayout textLayout = view.findViewById(R.id.check_status_text_layout);
int verticalMargin = getDimensionPixelOffset(view, getStatusTextMargin(status));
......@@ -289,14 +302,15 @@ class PasswordCheckViewBinder {
statusDescription.setVisibility(getStatusDescriptionVisibility(status));
}
private static String getStatusMessage(View view, @PasswordCheckUIStatus int status,
Integer compromisedCredentialsCount, Pair<Integer, Integer> progress) {
private static CharSequence getStatusMessage(View view, @PasswordCheckUIStatus int status,
Integer compromisedCredentialsCount, Pair<Integer, Integer> progress,
Runnable launchCheckupInAccount) {
switch (status) {
case PasswordCheckUIStatus.IDLE:
assert compromisedCredentialsCount != null;
return compromisedCredentialsCount == 0
? getString(view, R.string.password_check_status_message_idle_no_leaks)
: view.getContext().getResources().getQuantityString(
: getResources(view).getQuantityString(
R.plurals.password_check_status_message_idle_with_leaks,
compromisedCredentialsCount, compromisedCredentialsCount);
case PasswordCheckUIStatus.RUNNING:
......@@ -317,8 +331,12 @@ class PasswordCheckViewBinder {
case PasswordCheckUIStatus.ERROR_QUOTA_LIMIT:
return getString(view, R.string.password_check_status_message_error_quota_limit);
case PasswordCheckUIStatus.ERROR_QUOTA_LIMIT_ACCOUNT_CHECK:
return getString(view,
R.string.password_check_status_message_error_quota_limit_account_check);
NoUnderlineClickableSpan linkSpan = new NoUnderlineClickableSpan(
getResources(view), unusedView -> launchCheckupInAccount.run());
return SpanApplier.applySpans(
getString(view,
R.string.password_check_status_message_error_quota_limit_account_check),
new SpanApplier.SpanInfo("<link>", "</link>", linkSpan));
case PasswordCheckUIStatus.ERROR_UNKNOWN:
return getString(view, R.string.password_check_status_message_error_unknown);
default:
......@@ -348,7 +366,7 @@ class PasswordCheckViewBinder {
private static String getStatusDescription(View view, Long checkTimestamp) {
if (checkTimestamp == null) return null;
Resources res = view.getContext().getResources();
Resources res = getResources(view);
return res.getString(R.string.password_check_status_description_idle,
getTimestamp(res, System.currentTimeMillis() - checkTimestamp));
}
......@@ -468,11 +486,15 @@ class PasswordCheckViewBinder {
}
private static String getString(View view, int resourceId) {
return view.getContext().getResources().getString(resourceId);
return getResources(view).getString(resourceId);
}
private static int getDimensionPixelOffset(View view, int resourceId) {
return view.getContext().getResources().getDimensionPixelOffset(resourceId);
return getResources(view).getDimensionPixelOffset(resourceId);
}
private static Resources getResources(View view) {
return view.getContext().getResources();
}
private static void setTintListForCompoundDrawables(
......
......@@ -203,7 +203,7 @@
Chrome couldn't check all passwords. Try again tomorrow.
</message>
<message name="IDS_PASSWORD_CHECK_STATUS_MESSAGE_ERROR_QUOTA_LIMIT_ACCOUNT_CHECK" desc="Error message explaining that the password check failed because the user has exceeded their quota and redirecting to check in the Google Account.">
Chrome couldn't check all passwords. Try again tomorrow or check passwords in your Google Account.
Chrome couldn't check all passwords. Try again tomorrow or <ph name="BEGIN_LINK">&lt;link&gt;</ph>check passwords in your Google Account<ph name="END_LINK">&lt;/link&gt;</ph>.
</message>
<message name="IDS_PASSWORD_CHECK_STATUS_MESSAGE_ERROR_SIGNED_OUT" desc="Error message explaining that the password check failed because the user is signed-out.">
Chrome can check your passwords when you sign in with your Google Account.
......
d7b9987fb0a45cf5f829ba2750b0d9dcb8564a60
\ No newline at end of file
c4546cf199aa6314ead807fa1fc0e1ed8b779a83
\ No newline at end of file
......@@ -4,6 +4,7 @@
package org.chromium.chrome.browser.password_check;
import android.app.Activity;
import android.content.Context;
/**
......@@ -104,6 +105,11 @@ public interface PasswordCheck extends PasswordCheckComponentUi.Delegate {
*/
int getSavedPasswordsCount();
/**
* Launch the password check in the Google Account.
*/
void launchCheckupInAccount(Activity activity);
/**
* Starts the password check, if one is not running already.
*/
......
......@@ -28,6 +28,7 @@ import static org.chromium.chrome.browser.password_check.PasswordCheckProperties
import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.HeaderProperties.CHECK_STATUS;
import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.HeaderProperties.CHECK_TIMESTAMP;
import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.HeaderProperties.COMPROMISED_CREDENTIALS_COUNT;
import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.HeaderProperties.LAUNCH_ACCOUNT_CHECKUP_ACTION;
import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.HeaderProperties.RESTART_BUTTON_ACTION;
import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.HeaderProperties.UNKNOWN_PROGRESS;
import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.ITEMS;
......@@ -123,6 +124,8 @@ public class PasswordCheckViewTest {
@Mock
private PasswordCheckCoordinator.CredentialEventHandler mMockHandler;
@Mock
private Runnable mMockLaunchCheckupInAccount;
@Mock
private Runnable mMockStartButtonCallback;
@Rule
......@@ -253,11 +256,11 @@ public class PasswordCheckViewTest {
@Test
@MediumTest
public void testStatusRunnningText() {
public void testStatusRunningText() {
runOnUiThreadBlocking(
() -> { mModel.get(ITEMS).add(buildHeader(RUNNING, UNKNOWN_PROGRESS)); });
waitForListViewToHaveLength(1);
assertThat(getHeaderMessage().getText(),
assertThat(getHeaderMessageText(),
is(getString(R.string.password_check_status_message_initial_running)));
assertThat(getHeaderMessage().getVisibility(), is(View.VISIBLE));
assertThat(getHeaderDescription().getVisibility(), is(View.GONE));
......@@ -270,7 +273,7 @@ public class PasswordCheckViewTest {
runOnUiThreadBlocking(
() -> { mModel.get(ITEMS).add(buildHeader(IDLE, 0, checkTimestamp)); });
waitForListViewToHaveLength(1);
assertThat(getHeaderMessage().getText(),
assertThat(getHeaderMessageText(),
is(getString(R.string.password_check_status_message_idle_no_leaks)));
assertThat(getHeaderMessage().getVisibility(), is(View.VISIBLE));
assertThat(getHeaderDescription().getVisibility(), is(View.VISIBLE));
......@@ -283,7 +286,7 @@ public class PasswordCheckViewTest {
runOnUiThreadBlocking(
() -> { mModel.get(ITEMS).add(buildHeader(IDLE, LEAKS_COUNT, checkTimestamp)); });
waitForListViewToHaveLength(1);
assertThat(getHeaderMessage().getText(),
assertThat(getHeaderMessageText(),
is(mPasswordCheckView.getContext().getResources().getQuantityString(
R.plurals.password_check_status_message_idle_with_leaks, LEAKS_COUNT,
LEAKS_COUNT)));
......@@ -296,7 +299,7 @@ public class PasswordCheckViewTest {
public void testStatusErrorOfflineText() {
runOnUiThreadBlocking(() -> { mModel.get(ITEMS).add(buildHeader(ERROR_OFFLINE)); });
waitForListViewToHaveLength(1);
assertThat(getHeaderMessage().getText(),
assertThat(getHeaderMessageText(),
is(getString(R.string.password_check_status_message_error_offline)));
assertThat(getHeaderMessage().getVisibility(), is(View.VISIBLE));
assertThat(getHeaderDescription().getVisibility(), is(View.GONE));
......@@ -307,7 +310,7 @@ public class PasswordCheckViewTest {
public void testStatusErrorNoPasswordsText() {
runOnUiThreadBlocking(() -> { mModel.get(ITEMS).add(buildHeader(ERROR_NO_PASSWORDS)); });
waitForListViewToHaveLength(1);
assertThat(getHeaderMessage().getText(),
assertThat(getHeaderMessageText(),
is(getString(R.string.password_check_status_message_error_no_passwords)));
assertThat(getHeaderMessage().getVisibility(), is(View.VISIBLE));
assertThat(getHeaderDescription().getVisibility(), is(View.GONE));
......@@ -318,7 +321,7 @@ public class PasswordCheckViewTest {
public void testStatusErrorQuotaLimitText() {
runOnUiThreadBlocking(() -> { mModel.get(ITEMS).add(buildHeader(ERROR_QUOTA_LIMIT)); });
waitForListViewToHaveLength(1);
assertThat(getHeaderMessage().getText(),
assertThat(getHeaderMessageText(),
is(getString(R.string.password_check_status_message_error_quota_limit)));
assertThat(getHeaderMessage().getVisibility(), is(View.VISIBLE));
assertThat(getHeaderDescription().getVisibility(), is(View.GONE));
......@@ -330,11 +333,14 @@ public class PasswordCheckViewTest {
runOnUiThreadBlocking(
() -> { mModel.get(ITEMS).add(buildHeader(ERROR_QUOTA_LIMIT_ACCOUNT_CHECK)); });
waitForListViewToHaveLength(1);
assertThat(getHeaderMessage().getText(),
is(getString(
R.string.password_check_status_message_error_quota_limit_account_check)));
assertThat(getHeaderMessageText(),
is(getString(R.string.password_check_status_message_error_quota_limit_account_check)
.replace("<link>", "")
.replace("</link>", "")));
assertThat(getHeaderMessage().getVisibility(), is(View.VISIBLE));
assertThat(getHeaderDescription().getVisibility(), is(View.GONE));
TouchCommon.singleClickView(getHeaderMessage());
waitForEvent(mMockLaunchCheckupInAccount).run();
}
@Test
......@@ -342,7 +348,7 @@ public class PasswordCheckViewTest {
public void testStatusErrorSignedOutText() {
runOnUiThreadBlocking(() -> { mModel.get(ITEMS).add(buildHeader(ERROR_SIGNED_OUT)); });
waitForListViewToHaveLength(1);
assertThat(getHeaderMessage().getText(),
assertThat(getHeaderMessageText(),
is(getString(R.string.password_check_status_message_error_signed_out)));
assertThat(getHeaderMessage().getVisibility(), is(View.VISIBLE));
assertThat(getHeaderDescription().getVisibility(), is(View.GONE));
......@@ -353,7 +359,7 @@ public class PasswordCheckViewTest {
public void testStatusErrorUnknownText() {
runOnUiThreadBlocking(() -> { mModel.get(ITEMS).add(buildHeader(ERROR_UNKNOWN)); });
waitForListViewToHaveLength(1);
assertThat(getHeaderMessage().getText(),
assertThat(getHeaderMessageText(),
is(getString(R.string.password_check_status_message_error_unknown)));
assertThat(getHeaderMessage().getVisibility(), is(View.VISIBLE));
assertThat(getHeaderDescription().getVisibility(), is(View.GONE));
......@@ -588,6 +594,7 @@ public class PasswordCheckViewTest {
.with(CHECK_STATUS, status)
.with(CHECK_TIMESTAMP, checkTimestamp)
.with(COMPROMISED_CREDENTIALS_COUNT, compromisedCredentialsCount)
.with(LAUNCH_ACCOUNT_CHECKUP_ACTION, mMockLaunchCheckupInAccount)
.with(RESTART_BUTTON_ACTION, mMockStartButtonCallback)
.build());
}
......@@ -660,6 +667,10 @@ public class PasswordCheckViewTest {
return getStatus().findViewById(R.id.check_status_message);
}
private String getHeaderMessageText() {
return getHeaderMessage().getText().toString();
}
private TextView getHeaderSubtitle() {
return getStatus().findViewById(R.id.check_status_subtitle);
}
......
......@@ -28,6 +28,7 @@ import static org.chromium.chrome.browser.password_check.PasswordCheckProperties
import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.HeaderProperties.CHECK_STATUS;
import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.HeaderProperties.CHECK_TIMESTAMP;
import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.HeaderProperties.COMPROMISED_CREDENTIALS_COUNT;
import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.HeaderProperties.LAUNCH_ACCOUNT_CHECKUP_ACTION;
import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.HeaderProperties.RESTART_BUTTON_ACTION;
import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.HeaderProperties.UNKNOWN_PROGRESS;
import static org.chromium.chrome.browser.password_check.PasswordCheckProperties.ITEMS;
......@@ -100,7 +101,7 @@ public class PasswordCheckControllerTest {
mModel = PasswordCheckProperties.createDefaultModel();
mMediator = new PasswordCheckMediator(mChangePasswordDelegate, mReauthenticationHelper);
PasswordCheckFactory.setPasswordCheckForTesting(mPasswordCheck);
mMediator.initialize(mModel, mDelegate, PasswordCheckReferrer.PASSWORD_SETTINGS);
mMediator.initialize(mModel, mDelegate, PasswordCheckReferrer.PASSWORD_SETTINGS, () -> {});
}
@Test
......@@ -125,7 +126,7 @@ public class PasswordCheckControllerTest {
public void testInitializeHeaderWithLastStatusWhenComingFromSafetyCheck() {
clearInvocations(mPasswordCheck); // Clear invocations from setup code.
when(mPasswordCheck.getCheckStatus()).thenReturn(PasswordCheckUIStatus.IDLE);
mMediator.initialize(mModel, mDelegate, PasswordCheckReferrer.SAFETY_CHECK);
mMediator.initialize(mModel, mDelegate, PasswordCheckReferrer.SAFETY_CHECK, () -> {});
assertIdleHeader(mModel.get(ITEMS).get(0));
verify(mPasswordCheck, never()).startCheck();
}
......@@ -300,7 +301,6 @@ public class PasswordCheckControllerTest {
assertNull(header.model.get(CHECK_PROGRESS));
assertNotNull(header.model.get(CHECK_TIMESTAMP));
assertNotNull(header.model.get(COMPROMISED_CREDENTIALS_COUNT));
assertNotNull(header.model.get(RESTART_BUTTON_ACTION));
}
private void assertRunningHeader(
......@@ -309,7 +309,6 @@ public class PasswordCheckControllerTest {
assertThat(header.model.get(CHECK_PROGRESS), is(progress));
assertNull(header.model.get(CHECK_TIMESTAMP));
assertNull(header.model.get(COMPROMISED_CREDENTIALS_COUNT));
assertNotNull(header.model.get(RESTART_BUTTON_ACTION));
}
private void assertHeaderTypeWithStatus(
......@@ -317,5 +316,6 @@ public class PasswordCheckControllerTest {
assertThat(header.type, is(ItemType.HEADER));
assertThat(header.model.get(CHECK_STATUS), is(status));
assertNotNull(header.model.get(RESTART_BUTTON_ACTION));
assertNotNull(header.model.get(LAUNCH_ACCOUNT_CHECKUP_ACTION));
}
}
......@@ -9,7 +9,9 @@
#include "base/android/jni_string.h"
#include "chrome/browser/password_check/android/jni_headers/CompromisedCredential_jni.h"
#include "chrome/browser/password_check/android/jni_headers/PasswordCheckBridge_jni.h"
#include "chrome/browser/password_manager/android/password_checkup_launcher_helper.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "components/password_manager/core/browser/password_manager_util.h"
#include "components/password_manager/core/browser/ui/compromised_credentials_manager.h"
#include "url/android/gurl_android.h"
......@@ -89,6 +91,16 @@ void PasswordCheckBridge::GetCompromisedCredentials(
}
}
void PasswordCheckBridge::LaunchCheckupInAccount(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& activity) {
PasswordCheckupLauncherHelper::LaunchCheckupInAccountWithActivity(
env,
base::android::ConvertUTF8ToJavaString(
env, password_manager::GetPasswordCheckupURL().spec()),
activity);
}
void PasswordCheckBridge::UpdateCredential(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& credential,
......
......@@ -42,6 +42,11 @@ class PasswordCheckBridge : public PasswordCheckManager::Observer {
JNIEnv* env,
const base::android::JavaParamRef<jobjectArray>& credentials);
// Called by Java to launch a password check from the Google Account.
void LaunchCheckupInAccount(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& activity);
// Called by Java to update a single compromised credential in the password
// store.
void UpdateCredential(
......
......@@ -8,7 +8,7 @@
#include "base/android/jni_string.h"
#include "base/feature_list.h"
#include "chrome/android/chrome_jni_headers/PasswordChangeLauncher_jni.h"
#include "chrome/android/chrome_jni_headers/PasswordCheckupLauncher_jni.h"
#include "chrome/browser/password_manager/android/password_checkup_launcher_helper.h"
#include "chrome/browser/ui/android/passwords/credential_leak_dialog_view_android.h"
#include "chrome/common/url_constants.h"
#include "components/password_manager/core/browser/leak_detection_dialog_utils.h"
......@@ -61,10 +61,10 @@ void CredentialLeakControllerAndroid::OnAcceptDialog() {
if (ShouldCheckPasswords()) {
if (base::FeatureList::IsEnabled(
password_manager::features::kPasswordCheck)) {
Java_PasswordCheckupLauncher_launchLocalCheckup(
PasswordCheckupLauncherHelper::LaunchLocalCheckup(
env, window_android_->GetJavaObject());
} else {
Java_PasswordCheckupLauncher_launchCheckupInAccount(
PasswordCheckupLauncherHelper::LaunchCheckupInAccountWithWindowAndroid(
env,
base::android::ConvertUTF8ToJavaString(
env, password_manager::GetPasswordCheckupURL().spec()),
......
// 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/password_manager/android/password_checkup_launcher_helper.h"
#include "chrome/android/chrome_jni_headers/PasswordCheckupLauncher_jni.h"
// static
void PasswordCheckupLauncherHelper::LaunchCheckupInAccountWithWindowAndroid(
JNIEnv* env,
const base::android::JavaRef<jstring>& checkupUrl,
const base::android::JavaRef<jobject>& windowAndroid) {
Java_PasswordCheckupLauncher_launchCheckupInAccountWithWindowAndroid(
env, checkupUrl, windowAndroid);
}
// static
void PasswordCheckupLauncherHelper::LaunchLocalCheckup(
JNIEnv* env,
const base::android::JavaRef<jobject>& windowAndroid) {
Java_PasswordCheckupLauncher_launchLocalCheckup(env, windowAndroid);
}
// static
void PasswordCheckupLauncherHelper::LaunchCheckupInAccountWithActivity(
JNIEnv* env,
const base::android::JavaRef<jstring>& checkupUrl,
const base::android::JavaRef<jobject>& activity) {
Java_PasswordCheckupLauncher_launchCheckupInAccountWithActivity(
env, checkupUrl, activity);
}
// 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_PASSWORD_MANAGER_ANDROID_PASSWORD_CHECKUP_LAUNCHER_HELPER_H_
#define CHROME_BROWSER_PASSWORD_MANAGER_ANDROID_PASSWORD_CHECKUP_LAUNCHER_HELPER_H_
#include "base/android/jni_android.h"
#include "base/android/jni_string.h"
// Helper class used to access the methods of the java class
// PasswordCheckupLauncher from multiple native side locations
class PasswordCheckupLauncherHelper {
public:
// Launch the bulk password check in the Google Account
static void LaunchCheckupInAccountWithWindowAndroid(
JNIEnv* env,
const base::android::JavaRef<jstring>& checkupUrl,
const base::android::JavaRef<jobject>& windowAndroid);
// Launch the bulk password check locally
static void LaunchLocalCheckup(
JNIEnv* env,
const base::android::JavaRef<jobject>& windowAndroid);
// Launch the bulk password check in the Google Account using an activity
// rather than a WindowAndroid
static void LaunchCheckupInAccountWithActivity(
JNIEnv* env,
const base::android::JavaRef<jstring>& checkupUrl,
const base::android::JavaRef<jobject>& activity);
};
#endif // CHROME_BROWSER_PASSWORD_MANAGER_ANDROID_PASSWORD_CHECKUP_LAUNCHER_HELPER_H_
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