1 // Copyright 2019 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 package org.chromium.chrome.browser.password_manager.settings; 6 7 import android.os.Bundle; 8 import android.text.InputType; 9 import android.text.TextUtils; 10 import android.view.LayoutInflater; 11 import android.view.Menu; 12 import android.view.MenuInflater; 13 import android.view.MenuItem; 14 import android.view.View; 15 import android.view.ViewGroup; 16 import android.view.WindowManager; 17 import android.widget.EditText; 18 import android.widget.ImageButton; 19 import androidx.fragment.app.Fragment; 20 import com.google.android.material.textfield.TextInputLayout; 21 import org.chromium.chrome.R; 22 import org.chromium.ui.widget.Toast; 23 24 /** 25 * Password entry editor that allows editing passwords stored in Chrome. 26 */ 27 public class PasswordEntryEditor extends Fragment { 28 static final String VIEW_BUTTON_PRESSED = "viewButtonPressed"; 29 public static final String CREDENTIAL_URL = "credentialUrl"; 30 public static final String CREDENTIAL_NAME = "credentialName"; 31 public static final String CREDENTIAL_PASSWORD = "credentialPassword"; 32 33 private EditText mSiteText; 34 private EditText mUsernameText; 35 private EditText mPasswordText; 36 private TextInputLayout mPasswordLabel; 37 38 private ImageButton mViewPasswordButton; 39 40 private Runnable mPendingAction; 41 42 @Override onCreateView( LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)43 public View onCreateView( 44 LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 45 setHasOptionsMenu(true); 46 getActivity().setTitle(R.string.password_entry_viewer_edit_stored_password_action_title); 47 return inflater.inflate(R.layout.password_entry_editor, container, false); 48 } 49 50 @Override onViewCreated(View view, Bundle savedInstanceState)51 public void onViewCreated(View view, Bundle savedInstanceState) { 52 super.onViewCreated(view, savedInstanceState); 53 mSiteText = (EditText) view.findViewById(R.id.site_edit); 54 mUsernameText = (EditText) view.findViewById(R.id.username_edit); 55 mPasswordText = (EditText) view.findViewById(R.id.password_edit); 56 mPasswordLabel = (TextInputLayout) view.findViewById(R.id.password_label); 57 mViewPasswordButton = view.findViewById(R.id.password_entry_editor_view_password); 58 59 mSiteText.setText(getArguments().getString(CREDENTIAL_URL)); 60 mUsernameText.setText(getArguments().getString(CREDENTIAL_NAME)); 61 mPasswordText.setText(getArguments().getString(CREDENTIAL_PASSWORD)); 62 maskPassword(); 63 } 64 65 @Override onResume()66 public void onResume() { 67 super.onResume(); 68 boolean hasValidReauth = ReauthenticationManager.authenticationStillValid( 69 ReauthenticationManager.ReauthScope.ONE_AT_A_TIME); 70 if (!hasValidReauth) { 71 maskPassword(); 72 } else if (mPendingAction != null) { 73 mPendingAction.run(); 74 } 75 mPendingAction = null; 76 } 77 78 @Override onCreateOptionsMenu(Menu menu, MenuInflater inflater)79 public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 80 inflater.inflate(R.menu.password_entry_editor_action_bar_menu, menu); 81 } 82 83 @Override onOptionsItemSelected(MenuItem item)84 public boolean onOptionsItemSelected(MenuItem item) { 85 int id = item.getItemId(); 86 if (id == R.id.action_save_edited_password) { 87 saveChanges(); 88 return true; 89 } 90 return super.onOptionsItemSelected(item); 91 } 92 maskPassword()93 private void maskPassword() { 94 getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_SECURE); 95 mPasswordText.setInputType(InputType.TYPE_CLASS_TEXT 96 | InputType.TYPE_TEXT_VARIATION_PASSWORD | InputType.TYPE_TEXT_FLAG_MULTI_LINE); 97 mViewPasswordButton.setImageResource(R.drawable.ic_visibility_black); 98 mViewPasswordButton.setOnClickListener( 99 (unusedView) 100 -> this.performActionAfterReauth(this::unmaskPassword, 101 R.string.lockscreen_description_view, 102 R.string.password_entry_view_set_screen_lock)); 103 } 104 unmaskPassword()105 private void unmaskPassword() { 106 getActivity().getWindow().setFlags( 107 WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE); 108 mPasswordText.setInputType(InputType.TYPE_CLASS_TEXT 109 | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD 110 | InputType.TYPE_TEXT_FLAG_MULTI_LINE); 111 mViewPasswordButton.setImageResource(R.drawable.ic_visibility_off_black); 112 mViewPasswordButton.setOnClickListener((unusedView) -> this.maskPassword()); 113 } 114 saveChanges()115 private void saveChanges() { 116 String password = mPasswordText.getText().toString(); 117 if (TextUtils.isEmpty(password)) { 118 mPasswordLabel.setError(getContext().getString( 119 R.string.pref_edit_dialog_field_required_validation_message)); 120 } else { 121 PasswordEditingDelegateProvider.getInstance() 122 .getPasswordEditingDelegate() 123 .editSavedPasswordEntry( 124 mUsernameText.getText().toString(), mPasswordText.getText().toString()); 125 getActivity().finish(); 126 } 127 } 128 performActionAfterReauth( Runnable action, int reasonString, int noScreenLockMessage)129 private void performActionAfterReauth( 130 Runnable action, int reasonString, int noScreenLockMessage) { 131 if (!ReauthenticationManager.isScreenLockSetUp(getActivity().getApplicationContext())) { 132 Toast.makeText(getActivity().getApplicationContext(), noScreenLockMessage, 133 Toast.LENGTH_LONG) 134 .show(); 135 return; 136 } 137 if (ReauthenticationManager.authenticationStillValid( 138 ReauthenticationManager.ReauthScope.ONE_AT_A_TIME)) { 139 action.run(); 140 return; 141 } 142 mPendingAction = action; 143 ReauthenticationManager.displayReauthenticationFragment(reasonString, View.NO_ID, 144 getParentFragmentManager(), ReauthenticationManager.ReauthScope.ONE_AT_A_TIME); 145 } 146 147 @Override onDestroy()148 public void onDestroy() { 149 super.onDestroy(); 150 PasswordEditingDelegateProvider.getInstance().getPasswordEditingDelegate().destroy(); 151 } 152 } 153