| Index: chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordEntryEditor.java
|
| diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordEntryEditor.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordEntryEditor.java
|
| index fc894c30947f1f7215739bd6dcf50b32c1053267..cdf82a92181ec78a0130d7f5f553758f46af32be 100644
|
| --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordEntryEditor.java
|
| +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordEntryEditor.java
|
| @@ -5,7 +5,15 @@
|
| package org.chromium.chrome.browser.preferences.password;
|
|
|
| import android.app.Fragment;
|
| +import android.app.FragmentManager;
|
| +import android.app.FragmentTransaction;
|
| +import android.app.KeyguardManager;
|
| +import android.content.ClipData;
|
| +import android.content.ClipboardManager;
|
| +import android.content.Context;
|
| +import android.os.Build;
|
| import android.os.Bundle;
|
| +import android.text.InputType;
|
| import android.view.LayoutInflater;
|
| import android.view.Menu;
|
| import android.view.MenuInflater;
|
| @@ -13,12 +21,15 @@ import android.view.MenuItem;
|
| import android.view.View;
|
| import android.view.ViewGroup;
|
| import android.widget.Button;
|
| +import android.widget.ImageButton;
|
| import android.widget.TextView;
|
|
|
| +import org.chromium.base.VisibleForTesting;
|
| import org.chromium.chrome.R;
|
| import org.chromium.chrome.browser.ChromeFeatureList;
|
| import org.chromium.chrome.browser.PasswordUIView;
|
| import org.chromium.chrome.browser.PasswordUIView.PasswordListObserver;
|
| +import org.chromium.ui.widget.Toast;
|
|
|
| /**
|
| * Password entry editor that allows to view and delete passwords stored in Chrome.
|
| @@ -32,7 +43,16 @@ public class PasswordEntryEditor extends Fragment {
|
| // If false this represents a saved name/password.
|
| private boolean mException;
|
|
|
| + @VisibleForTesting
|
| public static final String VIEW_PASSWORDS = "view-passwords";
|
| + private static final int VALID_REAUTHENTICATION_TIME_INTERVAL_MILLIS = 60000;
|
| +
|
| + private ClipboardManager mClipboard;
|
| + private KeyguardManager mKeyguardManager;
|
| + private Bundle mExtras;
|
| + private View mView;
|
| + private boolean mViewButtonPressed;
|
| + private boolean mCopyButtonPressed;
|
|
|
| @Override
|
| public void onCreate(Bundle savedInstanceState) {
|
| @@ -46,36 +66,68 @@ public class PasswordEntryEditor extends Fragment {
|
| public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
| Bundle savedInstanceState) {
|
| super.onCreate(savedInstanceState);
|
| - View v;
|
| - if (ChromeFeatureList.isEnabled(VIEW_PASSWORDS)) {
|
| - v = inflater.inflate(R.layout.password_entry_editor_interactive, container, false);
|
| + if (shouldDisplayInteractivePasswordEntryEditor()) {
|
| + mView = inflater.inflate(R.layout.password_entry_editor_interactive, container, false);
|
| } else {
|
| - v = inflater.inflate(R.layout.password_entry_editor, container, false);
|
| + mView = inflater.inflate(R.layout.password_entry_editor, container, false);
|
| }
|
| getActivity().setTitle(R.string.password_entry_editor_title);
|
| -
|
| - // Extras are set on this intent in class SavePasswordsPreferences.
|
| - Bundle extras = getArguments();
|
| - assert extras != null;
|
| - mID = extras.getInt(SavePasswordsPreferences.PASSWORD_LIST_ID);
|
| - String name = null;
|
| - if (extras.containsKey(SavePasswordsPreferences.PASSWORD_LIST_NAME)) {
|
| - name = extras.getString(SavePasswordsPreferences.PASSWORD_LIST_NAME);
|
| - }
|
| - TextView nameView = (TextView) v.findViewById(R.id.password_entry_editor_name);
|
| + mClipboard = (ClipboardManager) getActivity().getApplicationContext().getSystemService(
|
| + Context.CLIPBOARD_SERVICE);
|
| + // Extras are set on this intent in class {@link SavePasswordsPreferences}.
|
| + mExtras = getArguments();
|
| + assert mExtras != null;
|
| + mID = mExtras.getInt(SavePasswordsPreferences.PASSWORD_LIST_ID);
|
| + final String name = mExtras.containsKey(SavePasswordsPreferences.PASSWORD_LIST_NAME)
|
| + ? mExtras.getString(SavePasswordsPreferences.PASSWORD_LIST_NAME)
|
| + : null;
|
| + TextView nameView = (TextView) mView.findViewById(R.id.password_entry_editor_name);
|
| if (name != null) {
|
| nameView.setText(name);
|
| } else {
|
| nameView.setText(R.string.section_saved_passwords_exceptions);
|
| mException = true;
|
| }
|
| - String url = extras.getString(SavePasswordsPreferences.PASSWORD_LIST_URL);
|
| - TextView urlView = (TextView) v.findViewById(R.id.password_entry_editor_url);
|
| + final String url = mExtras.getString(SavePasswordsPreferences.PASSWORD_LIST_URL);
|
| + TextView urlView = (TextView) mView.findViewById(R.id.password_entry_editor_url);
|
| urlView.setText(url);
|
| - if (!ChromeFeatureList.isEnabled(VIEW_PASSWORDS)) {
|
| - hookupCancelDeleteButtons(v);
|
| + if (shouldDisplayInteractivePasswordEntryEditor()) {
|
| + mKeyguardManager =
|
| + (KeyguardManager) getActivity().getApplicationContext().getSystemService(
|
| + Context.KEYGUARD_SERVICE);
|
| + hidePassword();
|
| + hookupPasswordButtons();
|
| + hookupCopyUsernameButton();
|
| + hookupCopySiteButton();
|
| + } else {
|
| + hookupCancelDeleteButtons();
|
| }
|
| - return v;
|
| + return mView;
|
| + }
|
| +
|
| + public boolean shouldDisplayInteractivePasswordEntryEditor() {
|
| + return ChromeFeatureList.isEnabled(VIEW_PASSWORDS)
|
| + && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP;
|
| + }
|
| +
|
| + @Override
|
| + public void onResume() {
|
| + super.onResume();
|
| + if (authenticationStillValid()) {
|
| + if (mViewButtonPressed) displayPassword();
|
| +
|
| + if (mCopyButtonPressed) copyPassword();
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Verifies if authentication is still valid (the user authenticated less than 60 seconds ago
|
| + * and the startTime is not equal to 0.
|
| + */
|
| + private boolean authenticationStillValid() {
|
| + return SavePasswordsPreferences.getLastReauthTimeMillis() != 0
|
| + && System.currentTimeMillis() - SavePasswordsPreferences.getLastReauthTimeMillis()
|
| + < VALID_REAUTHENTICATION_TIME_INTERVAL_MILLIS;
|
| }
|
|
|
| @Override
|
| @@ -120,24 +172,139 @@ public class PasswordEntryEditor extends Fragment {
|
| passwordUIView.updatePasswordLists();
|
| }
|
|
|
| - private void hookupCancelDeleteButtons(View v) {
|
| - final Button deleteButton = (Button) v.findViewById(R.id.password_entry_editor_delete);
|
| - final Button cancelButton = (Button) v.findViewById(R.id.password_entry_editor_cancel);
|
| + private void hookupCancelDeleteButtons() {
|
| + final Button deleteButton = (Button) mView.findViewById(R.id.password_entry_editor_delete);
|
| + final Button cancelButton = (Button) mView.findViewById(R.id.password_entry_editor_cancel);
|
|
|
| deleteButton.setOnClickListener(new View.OnClickListener() {
|
| - @Override
|
| - public void onClick(View v) {
|
| - removeItem();
|
| - deleteButton.setEnabled(false);
|
| - cancelButton.setEnabled(false);
|
| - }
|
| - });
|
| + @Override
|
| + public void onClick(View v) {
|
| + removeItem();
|
| + deleteButton.setEnabled(false);
|
| + cancelButton.setEnabled(false);
|
| + }
|
| + });
|
|
|
| cancelButton.setOnClickListener(new View.OnClickListener() {
|
| - @Override
|
| - public void onClick(View v) {
|
| - getActivity().finish();
|
| + @Override
|
| + public void onClick(View v) {
|
| + getActivity().finish();
|
| + }
|
| + });
|
| + }
|
| +
|
| + private void hookupCopyUsernameButton() {
|
| + final ImageButton copyUsernameButton =
|
| + (ImageButton) mView.findViewById(R.id.password_entry_editor_copy_username);
|
| + copyUsernameButton.setOnClickListener(new View.OnClickListener() {
|
| + @Override
|
| + public void onClick(View v) {
|
| + ClipData clip = ClipData.newPlainText("username",
|
| + getArguments().getString(SavePasswordsPreferences.PASSWORD_LIST_NAME));
|
| + mClipboard.setPrimaryClip(clip);
|
| + Toast.makeText(getActivity().getApplicationContext(),
|
| + R.string.password_entry_editor_username_copied_into_clipboard,
|
| + Toast.LENGTH_SHORT)
|
| + .show();
|
| + }
|
| + });
|
| + }
|
| +
|
| + private void hookupCopySiteButton() {
|
| + final ImageButton copySiteButton =
|
| + (ImageButton) mView.findViewById(R.id.password_entry_editor_copy_site);
|
| + copySiteButton.setOnClickListener(new View.OnClickListener() {
|
| + @Override
|
| + public void onClick(View v) {
|
| + ClipData clip = ClipData.newPlainText("site",
|
| + getArguments().getString(SavePasswordsPreferences.PASSWORD_LIST_URL));
|
| + mClipboard.setPrimaryClip(clip);
|
| + Toast.makeText(getActivity().getApplicationContext(),
|
| + R.string.password_entry_editor_site_copied_into_clipboard,
|
| + Toast.LENGTH_SHORT)
|
| + .show();
|
| + }
|
| + });
|
| + }
|
| +
|
| + private void changeHowPasswordIsDisplayed(int visibilityIcon, int inputType) {
|
| + TextView passwordView = (TextView) mView.findViewById(R.id.password_entry_editor_password);
|
| + ImageButton viewPasswordButton =
|
| + (ImageButton) mView.findViewById(R.id.password_entry_editor_view_password);
|
| + passwordView.setText(mExtras.getString(SavePasswordsPreferences.PASSWORD_LIST_PASSWORD));
|
| + passwordView.setInputType(inputType);
|
| + viewPasswordButton.setImageResource(visibilityIcon);
|
| + }
|
| +
|
| + private void displayPassword() {
|
| + changeHowPasswordIsDisplayed(
|
| + R.drawable.ic_visibility_off, InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD);
|
| + }
|
| +
|
| + private void hidePassword() {
|
| + changeHowPasswordIsDisplayed(R.drawable.ic_visibility,
|
| + InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
|
| + }
|
| +
|
| + private void copyPassword() {
|
| + ClipData clip = ClipData.newPlainText("password",
|
| + getArguments().getString(SavePasswordsPreferences.PASSWORD_LIST_PASSWORD));
|
| + mClipboard.setPrimaryClip(clip);
|
| + Toast.makeText(getActivity().getApplicationContext(),
|
| + R.string.password_entry_editor_password_copied_into_clipboard,
|
| + Toast.LENGTH_SHORT)
|
| + .show();
|
| + }
|
| +
|
| + private void displayReauthenticationFragment() {
|
| + Fragment passwordReauthentication = new PasswordReauthenticationFragment();
|
| + FragmentManager fragmentManager = getFragmentManager();
|
| + FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
|
| + fragmentTransaction.replace(
|
| + R.id.password_entry_editor_interactive, passwordReauthentication);
|
| + fragmentTransaction.addToBackStack(null);
|
| + fragmentTransaction.commit();
|
| + }
|
| +
|
| + private void hookupPasswordButtons() {
|
| + final ImageButton copyPasswordButton =
|
| + (ImageButton) mView.findViewById(R.id.password_entry_editor_copy_password);
|
| + final ImageButton viewPasswordButton =
|
| + (ImageButton) mView.findViewById(R.id.password_entry_editor_view_password);
|
| + copyPasswordButton.setOnClickListener(new View.OnClickListener() {
|
| + @Override
|
| + public void onClick(View v) {
|
| + if (!mKeyguardManager.isKeyguardSecure()) {
|
| + Toast.makeText(getActivity().getApplicationContext(),
|
| + R.string.password_entry_editor_set_lock_screen, Toast.LENGTH_LONG)
|
| + .show();
|
| + } else if (authenticationStillValid()) {
|
| + copyPassword();
|
| + } else {
|
| + mCopyButtonPressed = true;
|
| + displayReauthenticationFragment();
|
| }
|
| - });
|
| + }
|
| + });
|
| + viewPasswordButton.setOnClickListener(new View.OnClickListener() {
|
| + @Override
|
| + public void onClick(View v) {
|
| + TextView passwordView =
|
| + (TextView) mView.findViewById(R.id.password_entry_editor_password);
|
| + if (!mKeyguardManager.isKeyguardSecure()) {
|
| + Toast.makeText(getActivity().getApplicationContext(),
|
| + R.string.password_entry_editor_set_lock_screen, Toast.LENGTH_LONG)
|
| + .show();
|
| + } else if (passwordView.getInputType()
|
| + == InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD) {
|
| + hidePassword();
|
| + } else if (authenticationStillValid()) {
|
| + displayPassword();
|
| + } else {
|
| + mViewButtonPressed = true;
|
| + displayReauthenticationFragment();
|
| + }
|
| + }
|
| + });
|
| }
|
| }
|
|
|