1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.browser; 18 19 import android.app.Fragment; 20 import android.content.Context; 21 import android.os.Bundle; 22 import android.os.Handler; 23 import android.os.Message; 24 import android.text.Editable; 25 import android.text.TextWatcher; 26 import android.util.Log; 27 import android.view.View; 28 import android.view.ViewGroup; 29 import android.view.View.OnClickListener; 30 import android.view.LayoutInflater; 31 import android.view.Menu; 32 import android.view.MenuInflater; 33 import android.view.MenuItem; 34 import android.view.inputmethod.InputMethodManager; 35 import android.webkit.WebSettings.AutoFillProfile; 36 import android.widget.Button; 37 import android.widget.EditText; 38 import android.widget.Toast; 39 40 public class AutoFillSettingsFragment extends Fragment { 41 42 private static final String LOGTAG = "AutoFillSettingsFragment"; 43 44 private EditText mFullNameEdit; 45 private EditText mEmailEdit; 46 private EditText mCompanyEdit; 47 private EditText mAddressLine1Edit; 48 private EditText mAddressLine2Edit; 49 private EditText mCityEdit; 50 private EditText mStateEdit; 51 private EditText mZipEdit; 52 private EditText mCountryEdit; 53 private EditText mPhoneEdit; 54 55 private Button mSaveButton; 56 57 // Used to display toast after DB interactions complete. 58 private Handler mHandler; 59 private BrowserSettings mSettings; 60 61 private final static int PROFILE_SAVED_MSG = 100; 62 private final static int PROFILE_DELETED_MSG = 101; 63 64 // For now we support just one profile so it's safe to hardcode the 65 // id to 1 here. In the future this unique identifier will be set 66 // dynamically. 67 private int mUniqueId = 1; 68 69 private class PhoneNumberValidator implements TextWatcher { 70 // Keep in sync with kPhoneNumberLength in chrome/browser/autofill/phone_number.cc 71 private static final int PHONE_NUMBER_LENGTH = 7; 72 private static final String PHONE_NUMBER_SEPARATORS_REGEX = "[\\s\\.\\(\\)-]"; 73 74 public void afterTextChanged(Editable s) { 75 String phoneNumber = s.toString(); 76 int phoneNumberLength = phoneNumber.length(); 77 78 // Strip out any phone number separators. 79 phoneNumber = phoneNumber.replaceAll(PHONE_NUMBER_SEPARATORS_REGEX, ""); 80 81 int strippedPhoneNumberLength = phoneNumber.length(); 82 83 if (phoneNumberLength > 0 && strippedPhoneNumberLength < PHONE_NUMBER_LENGTH) { 84 mPhoneEdit.setError(getResources().getText( 85 R.string.autofill_profile_editor_phone_number_invalid)); 86 } else { 87 mPhoneEdit.setError(null); 88 } 89 90 updateButtonState(); 91 } 92 93 public void beforeTextChanged(CharSequence s, int start, int count, int after) { 94 } 95 96 public void onTextChanged(CharSequence s, int start, int before, int count) { 97 } 98 } 99 100 private class FieldChangedListener implements TextWatcher { 101 public void afterTextChanged(Editable s) { 102 updateButtonState(); 103 } 104 105 public void beforeTextChanged(CharSequence s, int start, int count, int after) { 106 } 107 108 public void onTextChanged(CharSequence s, int start, int before, int count) { 109 } 110 111 } 112 113 private TextWatcher mFieldChangedListener = new FieldChangedListener(); 114 115 public AutoFillSettingsFragment() { 116 mHandler = new Handler() { 117 @Override 118 public void handleMessage(Message msg) { 119 Context c = getActivity(); 120 switch (msg.what) { 121 case PROFILE_SAVED_MSG: 122 if (c != null) { 123 Toast.makeText(c, R.string.autofill_profile_successful_save, 124 Toast.LENGTH_SHORT).show(); 125 closeEditor(); 126 } 127 break; 128 129 case PROFILE_DELETED_MSG: 130 if (c != null) { 131 Toast.makeText(c, R.string.autofill_profile_successful_delete, 132 Toast.LENGTH_SHORT).show(); 133 } 134 break; 135 } 136 } 137 }; 138 } 139 140 @Override 141 public void onCreate(Bundle savedState) { 142 super.onCreate(savedState); 143 setHasOptionsMenu(true); 144 mSettings = BrowserSettings.getInstance(); 145 } 146 147 @Override 148 public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 149 inflater.inflate(R.menu.autofill_profile_editor, menu); 150 } 151 152 @Override 153 public boolean onOptionsItemSelected(MenuItem item) { 154 if (item.getItemId() == R.id.autofill_profile_editor_delete_profile_menu_id) { 155 // Clear the UI. 156 mFullNameEdit.setText(""); 157 mEmailEdit.setText(""); 158 mCompanyEdit.setText(""); 159 mAddressLine1Edit.setText(""); 160 mAddressLine2Edit.setText(""); 161 mCityEdit.setText(""); 162 mStateEdit.setText(""); 163 mZipEdit.setText(""); 164 mCountryEdit.setText(""); 165 mPhoneEdit.setText(""); 166 167 // Update browser settings and native with a null profile. This will 168 // trigger the current profile to get deleted from the DB. 169 mSettings.setAutoFillProfile(null, 170 mHandler.obtainMessage(PROFILE_DELETED_MSG)); 171 updateButtonState(); 172 return true; 173 } 174 return false; 175 } 176 177 @Override 178 public View onCreateView(LayoutInflater inflater, ViewGroup container, 179 Bundle savedInstanceState) { 180 View v = inflater.inflate(R.layout.autofill_settings_fragment, container, false); 181 182 mFullNameEdit = (EditText)v.findViewById(R.id.autofill_profile_editor_name_edit); 183 mEmailEdit = (EditText)v.findViewById(R.id.autofill_profile_editor_email_address_edit); 184 mCompanyEdit = (EditText)v.findViewById(R.id.autofill_profile_editor_company_name_edit); 185 mAddressLine1Edit = (EditText)v.findViewById( 186 R.id.autofill_profile_editor_address_line_1_edit); 187 mAddressLine2Edit = (EditText)v.findViewById( 188 R.id.autofill_profile_editor_address_line_2_edit); 189 mCityEdit = (EditText)v.findViewById(R.id.autofill_profile_editor_city_edit); 190 mStateEdit = (EditText)v.findViewById(R.id.autofill_profile_editor_state_edit); 191 mZipEdit = (EditText)v.findViewById(R.id.autofill_profile_editor_zip_code_edit); 192 mCountryEdit = (EditText)v.findViewById(R.id.autofill_profile_editor_country_edit); 193 mPhoneEdit = (EditText)v.findViewById(R.id.autofill_profile_editor_phone_number_edit); 194 195 mFullNameEdit.addTextChangedListener(mFieldChangedListener); 196 mEmailEdit.addTextChangedListener(mFieldChangedListener); 197 mCompanyEdit.addTextChangedListener(mFieldChangedListener); 198 mAddressLine1Edit.addTextChangedListener(mFieldChangedListener); 199 mAddressLine2Edit.addTextChangedListener(mFieldChangedListener); 200 mCityEdit.addTextChangedListener(mFieldChangedListener); 201 mStateEdit.addTextChangedListener(mFieldChangedListener); 202 mZipEdit.addTextChangedListener(mFieldChangedListener); 203 mCountryEdit.addTextChangedListener(mFieldChangedListener); 204 mPhoneEdit.addTextChangedListener(new PhoneNumberValidator()); 205 206 mSaveButton = (Button)v.findViewById(R.id.autofill_profile_editor_save_button); 207 mSaveButton.setOnClickListener(new OnClickListener() { 208 public void onClick(View button) { 209 AutoFillProfile newProfile = new AutoFillProfile( 210 mUniqueId, 211 mFullNameEdit.getText().toString(), 212 mEmailEdit.getText().toString(), 213 mCompanyEdit.getText().toString(), 214 mAddressLine1Edit.getText().toString(), 215 mAddressLine2Edit.getText().toString(), 216 mCityEdit.getText().toString(), 217 mStateEdit.getText().toString(), 218 mZipEdit.getText().toString(), 219 mCountryEdit.getText().toString(), 220 mPhoneEdit.getText().toString()); 221 222 mSettings.setAutoFillProfile(newProfile, 223 mHandler.obtainMessage(PROFILE_SAVED_MSG)); 224 } 225 }); 226 227 // Populate the text boxes with any pre existing AutoFill data. 228 AutoFillProfile activeProfile = mSettings.getAutoFillProfile(); 229 if (activeProfile != null) { 230 mFullNameEdit.setText(activeProfile.getFullName()); 231 mEmailEdit.setText(activeProfile.getEmailAddress()); 232 mCompanyEdit.setText(activeProfile.getCompanyName()); 233 mAddressLine1Edit.setText(activeProfile.getAddressLine1()); 234 mAddressLine2Edit.setText(activeProfile.getAddressLine2()); 235 mCityEdit.setText(activeProfile.getCity()); 236 mStateEdit.setText(activeProfile.getState()); 237 mZipEdit.setText(activeProfile.getZipCode()); 238 mCountryEdit.setText(activeProfile.getCountry()); 239 mPhoneEdit.setText(activeProfile.getPhoneNumber()); 240 } 241 242 updateButtonState(); 243 244 return v; 245 } 246 247 public void updateButtonState() { 248 249 boolean valid = (mFullNameEdit.getText().toString().length() > 0 || 250 mEmailEdit.getText().toString().length() > 0 || 251 mCompanyEdit.getText().toString().length() > 0 || 252 mAddressLine1Edit.getText().toString().length() > 0 || 253 mAddressLine2Edit.getText().toString().length() > 0 || 254 mCityEdit.getText().toString().length() > 0 || 255 mStateEdit.getText().toString().length() > 0 || 256 mZipEdit.getText().toString().length() > 0 || 257 mCountryEdit.getText().toString().length() > 0) && 258 mPhoneEdit.getError() == null; 259 260 // Only enable the save buttons if we have at least one field completed 261 // and the phone number (if present is valid). 262 mSaveButton.setEnabled(valid); 263 } 264 265 private void closeEditor() { 266 // Hide the IME if the user wants to close while an EditText has focus 267 InputMethodManager imm = (InputMethodManager) getActivity().getSystemService( 268 Context.INPUT_METHOD_SERVICE); 269 imm.hideSoftInputFromWindow(getView().getWindowToken(), 0); 270 if (getFragmentManager().getBackStackEntryCount() > 0) { 271 getFragmentManager().popBackStack(); 272 } else { 273 getActivity().finish(); 274 } 275 } 276 } 277