Commit 4cafb7d5 authored by Andrey Zaytsev's avatar Andrey Zaytsev Committed by Commit Bot

Safety check on Android: added compromised passwords string and state

Bug: 1070620
Change-Id: I6b6c41eaaabf3a1e7c8ca59fcf7fbbce18f30cc8
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2352742
Auto-Submit: Andrey Zaytsev <andzaytsev@google.com>
Reviewed-by: default avatarMartin Šrámek <msramek@chromium.org>
Commit-Queue: Andrey Zaytsev <andzaytsev@google.com>
Cr-Commit-Position: refs/heads/master@{#798093}
parent 51adf6a9
......@@ -369,7 +369,9 @@ class SafetyCheckMediator implements PasswordCheck.Observer, SafetyCheckCommonOb
/** Applies the results of the password check to the model. Only called when data is loaded. */
private void updatePasswordsStateOnDataLoaded() {
// Always display the compromised state.
if (mPasswordCheck.getCompromisedCredentialsCount() != 0) {
int compromised = mPasswordCheck.getCompromisedCredentialsCount();
if (compromised != 0) {
mModel.set(SafetyCheckProperties.COMPROMISED_PASSWORDS, compromised);
mModel.set(SafetyCheckProperties.PASSWORDS_STATE, PasswordsState.COMPROMISED_EXIST);
} else if (mLoadStage == PasswordCheckLoadStage.INITIAL_WAIT_FOR_LOAD
&& !mShowSafePasswordState) {
......
......@@ -19,6 +19,8 @@ import java.lang.annotation.RetentionPolicy;
class SafetyCheckProperties {
/** State of the passwords check, one of the {@link PasswordsState} values. */
static final WritableIntPropertyKey PASSWORDS_STATE = new WritableIntPropertyKey();
/** Number of compromised passwords; only used when PASSWORDS_STATE is COMPROMISED_EXIST. */
static final WritableIntPropertyKey COMPROMISED_PASSWORDS = new WritableIntPropertyKey();
/** State of the Safe Browsing check, one of the {@link SafeBrowsingState} values. */
static final WritableIntPropertyKey SAFE_BROWSING_STATE = new WritableIntPropertyKey();
/** State of the updates check, one of the {@link UpdatesState} values. */
......@@ -125,13 +127,15 @@ class SafetyCheckProperties {
int ERROR = 5;
}
static final PropertyKey[] ALL_KEYS = new PropertyKey[] {PASSWORDS_STATE, SAFE_BROWSING_STATE,
UPDATES_STATE, PASSWORDS_CLICK_LISTENER, SAFE_BROWSING_CLICK_LISTENER,
UPDATES_CLICK_LISTENER, SAFETY_CHECK_BUTTON_CLICK_LISTENER, LAST_RUN_TIMESTAMP};
static final PropertyKey[] ALL_KEYS =
new PropertyKey[] {PASSWORDS_STATE, COMPROMISED_PASSWORDS, SAFE_BROWSING_STATE,
UPDATES_STATE, PASSWORDS_CLICK_LISTENER, SAFE_BROWSING_CLICK_LISTENER,
UPDATES_CLICK_LISTENER, SAFETY_CHECK_BUTTON_CLICK_LISTENER, LAST_RUN_TIMESTAMP};
static PropertyModel createSafetyCheckModel() {
return new PropertyModel.Builder(ALL_KEYS)
.with(PASSWORDS_STATE, PasswordsState.UNCHECKED)
.with(COMPROMISED_PASSWORDS, 0)
.with(SAFE_BROWSING_STATE, SafeBrowsingState.UNCHECKED)
.with(UPDATES_STATE, UpdatesState.UNCHECKED)
.with(LAST_RUN_TIMESTAMP, 0)
......
......@@ -108,15 +108,24 @@ public class SafetyCheckSettingsFragment extends PreferenceFragmentCompat {
* @param statusString Resource ID of the new status string.
*/
public void updateElementStatus(String key, int statusString) {
if (statusString != 0) {
updateElementStatus(key, getContext().getString(statusString));
} else {
updateElementStatus(key, "");
}
}
/**
* Update the status string of a given Safety check element, e.g. Passwords.
* @param key An android:key String corresponding to Safety check element.
* @param statusString The new status string.
*/
public void updateElementStatus(String key, String statusString) {
Preference p = findPreference(key);
// If this is invoked before the preferences are created, do nothing.
if (p == null) {
return;
}
if (statusString != 0) {
p.setSummary(statusString);
} else {
p.setSummary("");
}
p.setSummary(statusString);
}
}
......@@ -24,31 +24,34 @@ class SafetyCheckViewBinder {
private static final long H_TO_MS = 60 * MIN_TO_MS;
private static final long DAY_TO_MS = 24 * H_TO_MS;
private static int getStringForPasswords(@PasswordsState int state) {
private static String getStringForPasswords(
Context context, PropertyModel model, @PasswordsState int state) {
switch (state) {
case PasswordsState.UNCHECKED:
case PasswordsState.CHECKING:
return 0;
return "";
case PasswordsState.NO_PASSWORDS:
return R.string.safety_check_passwords_no_passwords;
return context.getString(R.string.safety_check_passwords_no_passwords);
case PasswordsState.SIGNED_OUT:
return R.string.safety_check_passwords_error_signed_out;
return context.getString(R.string.safety_check_passwords_error_signed_out);
case PasswordsState.QUOTA_LIMIT:
return R.string.safety_check_passwords_error_quota_limit;
return context.getString(R.string.safety_check_passwords_error_quota_limit);
case PasswordsState.OFFLINE:
return R.string.safety_check_passwords_error_offline;
return context.getString(R.string.safety_check_passwords_error_offline);
case PasswordsState.ERROR:
return R.string.safety_check_passwords_error;
return context.getString(R.string.safety_check_passwords_error);
case PasswordsState.SAFE:
return R.string.safety_check_passwords_safe;
return context.getString(R.string.safety_check_passwords_safe);
case PasswordsState.COMPROMISED_EXIST:
// TODO(crbug.com/1070620): update the strings for all states once available.
return 0;
int compromised = model.get(SafetyCheckProperties.COMPROMISED_PASSWORDS);
return context.getResources().getQuantityString(
R.plurals.safety_check_passwords_compromised_exist, compromised,
compromised);
default:
assert false : "Unknown PasswordsState value.";
}
// Not reached.
return 0;
return "";
}
private static int getStatusIconForPasswords(@PasswordsState int state) {
......@@ -203,7 +206,8 @@ class SafetyCheckViewBinder {
if (SafetyCheckProperties.PASSWORDS_STATE == propertyKey) {
@PasswordsState
int state = model.get(SafetyCheckProperties.PASSWORDS_STATE);
fragment.updateElementStatus(PASSWORDS_KEY, getStringForPasswords(state));
fragment.updateElementStatus(
PASSWORDS_KEY, getStringForPasswords(fragment.getContext(), model, state));
SafetyCheckElementPreference preference = fragment.findPreference(PASSWORDS_KEY);
preference.setEnabled(true);
if (state == PasswordsState.UNCHECKED) {
......@@ -271,6 +275,9 @@ class SafetyCheckViewBinder {
SafetyCheckProperties.SAFETY_CHECK_BUTTON_CLICK_LISTENER));
} else if (SafetyCheckProperties.LAST_RUN_TIMESTAMP == propertyKey) {
displayTimestampText(model, fragment);
} else if (SafetyCheckProperties.COMPROMISED_PASSWORDS == propertyKey) {
// Do nothing - this is handled by the PASSWORDS_STATE update.
return;
} else {
assert false : "Unhandled property detected in SafetyCheckViewBinder!";
}
......
......@@ -10,6 +10,7 @@ import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.when;
import static org.chromium.chrome.browser.safety_check.SafetyCheckProperties.COMPROMISED_PASSWORDS;
import static org.chromium.chrome.browser.safety_check.SafetyCheckProperties.PASSWORDS_STATE;
import static org.chromium.chrome.browser.safety_check.SafetyCheckProperties.SAFE_BROWSING_STATE;
import static org.chromium.chrome.browser.safety_check.SafetyCheckProperties.UPDATES_STATE;
......@@ -200,6 +201,7 @@ public class SafetyCheckMediatorTest {
@Test
public void testPasswordsCheckHasLeaks() {
int numLeaks = 123;
doAnswer(invocation -> {
mMediator.onPasswordCheckStatusChanged(PasswordCheckUIStatus.IDLE);
return null;
......@@ -207,12 +209,13 @@ public class SafetyCheckMediatorTest {
.when(mPasswordCheck)
.startCheck();
when(mPasswordCheck.getSavedPasswordsCount()).thenReturn(199);
when(mPasswordCheck.getCompromisedCredentialsCount()).thenReturn(123);
when(mPasswordCheck.getCompromisedCredentialsCount()).thenReturn(numLeaks);
mMediator.performSafetyCheck();
mMediator.onCompromisedCredentialsFetchCompleted();
mMediator.onSavedPasswordsFetchCompleted();
assertEquals(PasswordsState.COMPROMISED_EXIST, mModel.get(PASSWORDS_STATE));
assertEquals(numLeaks, mModel.get(COMPROMISED_PASSWORDS));
}
@Test
......
......@@ -915,6 +915,11 @@ Your Google account may have other forms of browsing history like searches and a
<message name="IDS_SAFETY_CHECK_PASSWORDS_SAFE" desc="Text to display when no passwords are compromised.">
No compromised passwords found
</message>
<message name="IDS_SAFETY_CHECK_PASSWORDS_COMPROMISED_EXIST" desc="Text to display when there are compromised passwords.">
{NUM_PASSWORDS, plural,
=1 {1 compromised password}
other {# compromised passwords}}
</message>
<message name="IDS_SAFETY_CHECK_PASSWORDS_NO_PASSWORDS" desc="Text to display when no passwords are saved.">
No saved passwords
</message>
......
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