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