/*
* Copyright 2009-2016 Brian Pellin.
*
* This file is part of KeePassDroid.
*
* KeePassDroid is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* KeePassDroid is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with KeePassDroid. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.keepassdroid;
import java.util.Calendar;
import java.util.Date;
import java.util.UUID;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.text.InputType;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.TextView;
import android.widget.Toast;
import com.android.keepass.KeePass;
import com.android.keepass.R;
import com.keepassdroid.app.App;
import com.keepassdroid.database.PwDatabase;
import com.keepassdroid.database.PwEntry;
import com.keepassdroid.database.PwEntryV3;
import com.keepassdroid.database.PwEntryV4;
import com.keepassdroid.database.PwGroup;
import com.keepassdroid.database.PwGroupId;
import com.keepassdroid.database.PwGroupV3;
import com.keepassdroid.database.PwGroupV4;
import com.keepassdroid.database.edit.AddEntry;
import com.keepassdroid.database.edit.OnFinish;
import com.keepassdroid.database.edit.RunnableOnFinish;
import com.keepassdroid.database.edit.UpdateEntry;
import com.keepassdroid.icons.Icons;
import com.keepassdroid.utils.Types;
import com.keepassdroid.utils.Util;
public abstract class EntryEditActivity extends LockCloseHideActivity {
public static final String KEY_ENTRY = "entry";
public static final String KEY_PARENT = "parent";
public static final int RESULT_OK_ICON_PICKER = 1000;
public static final int RESULT_OK_PASSWORD_GENERATOR = RESULT_OK_ICON_PICKER + 1;
protected PwEntry mEntry;
private boolean mShowPassword = false;
protected boolean mIsNew;
protected int mSelectedIconID = -1;
public static void Launch(Activity act, PwEntry pw) {
Intent i;
if (pw instanceof PwEntryV3) {
i = new Intent(act, EntryEditActivityV3.class);
}
else if (pw instanceof PwEntryV4) {
i = new Intent(act, EntryEditActivityV4.class);
}
else {
throw new RuntimeException("Not yet implemented.");
}
i.putExtra(KEY_ENTRY, Types.UUIDtoBytes(pw.getUUID()));
act.startActivityForResult(i, 0);
}
public static void Launch(Activity act, PwGroup pw) {
Intent i;
if (pw instanceof PwGroupV3) {
i = new Intent(act, EntryEditActivityV3.class);
EntryEditActivityV3.putParentId(i, KEY_PARENT, (PwGroupV3)pw);
}
else if (pw instanceof PwGroupV4) {
i = new Intent(act, EntryEditActivityV4.class);
EntryEditActivityV4.putParentId(i, KEY_PARENT, (PwGroupV4)pw);
}
else {
throw new RuntimeException("Not yet implemented.");
}
act.startActivityForResult(i, 0);
}
protected abstract PwGroupId getParentGroupId(Intent i, String key);
@Override
protected void onCreate(Bundle savedInstanceState) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
mShowPassword = ! prefs.getBoolean(getString(R.string.maskpass_key), getResources().getBoolean(R.bool.maskpass_default));
super.onCreate(savedInstanceState);
setContentView(R.layout.entry_edit);
setResult(KeePass.EXIT_NORMAL);
// Likely the app has been killed exit the activity
Database db = App.getDB();
if ( ! db.Loaded() ) {
finish();
return;
}
Intent i = getIntent();
byte[] uuidBytes = i.getByteArrayExtra(KEY_ENTRY);
PwDatabase pm = db.pm;
if ( uuidBytes == null ) {
PwGroupId parentId = getParentGroupId(i, KEY_PARENT);
PwGroup parent = pm.groups.get(parentId);
mEntry = PwEntry.getInstance(parent);
mIsNew = true;
} else {
UUID uuid = Types.bytestoUUID(uuidBytes);
assert(uuid != null);
mEntry = pm.entries.get(uuid);
mIsNew = false;
fillData();
}
View scrollView = findViewById(R.id.entry_scroll);
scrollView.setScrollBarStyle(View.SCROLLBARS_INSIDE_INSET);
ImageButton iconButton = (ImageButton) findViewById(R.id.icon_button);
iconButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
IconPickerActivity.Launch(EntryEditActivity.this);
}
});
// Generate password button
Button generatePassword = (Button) findViewById(R.id.generate_button);
generatePassword.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
GeneratePasswordActivity.Launch(EntryEditActivity.this);
}
});
// Save button
Button save = (Button) findViewById(R.id.entry_save);
save.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
EntryEditActivity act = EntryEditActivity.this;
if (!validateBeforeSaving()) {
return;
}
PwEntry newEntry = populateNewEntry();
if ( newEntry.getTitle().equals(mEntry.getTitle()) ) {
setResult(KeePass.EXIT_REFRESH);
} else {
setResult(KeePass.EXIT_REFRESH_TITLE);
}
RunnableOnFinish task;
OnFinish onFinish = act.new AfterSave(new Handler());
if ( mIsNew ) {
task = AddEntry.getInstance(EntryEditActivity.this, App.getDB(), newEntry, onFinish);
} else {
task = new UpdateEntry(EntryEditActivity.this, App.getDB(), mEntry, newEntry, onFinish);
}
ProgressTask pt = new ProgressTask(act, task, R.string.saving_database);
pt.run();
}
});
// Cancel button
Button cancel = (Button) findViewById(R.id.entry_cancel);
cancel.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
finish();
}
});
// Respect mask password setting
if (mShowPassword) {
EditText pass = (EditText) findViewById(R.id.entry_password);
EditText conf = (EditText) findViewById(R.id.entry_confpassword);
pass.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD);
conf.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD);
}
}
protected boolean validateBeforeSaving() {
// Require title
String title = Util.getEditText(this, R.id.entry_title);
if ( title.length() == 0 ) {
Toast.makeText(this, R.string.error_title_required, Toast.LENGTH_LONG).show();
return false;
}
// Validate password
String pass = Util.getEditText(this, R.id.entry_password);
String conf = Util.getEditText(this, R.id.entry_confpassword);
if ( ! pass.equals(conf) ) {
Toast.makeText(this, R.string.error_pass_match, Toast.LENGTH_LONG).show();
return false;
}
return true;
}
protected PwEntry populateNewEntry() {
return populateNewEntry(null);
}
protected PwEntry populateNewEntry(PwEntry entry) {
PwEntry newEntry;
if (entry == null) {
newEntry = mEntry.clone(true);
}
else {
newEntry = entry;
}
Date now = Calendar.getInstance().getTime();
newEntry.setLastAccessTime(now);
newEntry.setLastModificationTime(now);
PwDatabase db = App.getDB().pm;
newEntry.setTitle(Util.getEditText(this, R.id.entry_title), db);
newEntry.setUrl(Util.getEditText(this, R.id.entry_url), db);
newEntry.setUsername(Util.getEditText(this, R.id.entry_user_name), db);
newEntry.setNotes(Util.getEditText(this, R.id.entry_comment), db);
newEntry.setPassword(Util.getEditText(this, R.id.entry_password), db);
return newEntry;
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
switch (resultCode)
{
case RESULT_OK_ICON_PICKER:
mSelectedIconID = data.getExtras().getInt(IconPickerActivity.KEY_ICON_ID);
ImageButton currIconButton = (ImageButton) findViewById(R.id.icon_button);
currIconButton.setImageResource(Icons.iconToResId(mSelectedIconID));
break;
case RESULT_OK_PASSWORD_GENERATOR:
String generatedPassword = data.getStringExtra("com.keepassdroid.password.generated_password");
EditText password = (EditText) findViewById(R.id.entry_password);
EditText confPassword = (EditText) findViewById(R.id.entry_confpassword);
password.setText(generatedPassword);
confPassword.setText(generatedPassword);
break;
case Activity.RESULT_CANCELED:
default:
break;
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.entry_edit, menu);
MenuItem togglePassword = menu.findItem(R.id.menu_toggle_pass);
if ( mShowPassword ) {
togglePassword.setTitle(R.string.menu_hide_password);
} else {
togglePassword.setTitle(R.string.menu_showpass);
}
return true;
}
public boolean onOptionsItemSelected(MenuItem item) {
switch ( item.getItemId() ) {
case R.id.menu_donate:
try {
Util.gotoUrl(this, R.string.donate_url);
} catch (ActivityNotFoundException e) {
Toast.makeText(this, R.string.error_failed_to_launch_link, Toast.LENGTH_LONG).show();
return false;
}
return true;
case R.id.menu_toggle_pass:
if ( mShowPassword ) {
item.setTitle(R.string.menu_showpass);
mShowPassword = false;
} else {
item.setTitle(R.string.menu_hide_password);
mShowPassword = true;
}
setPasswordStyle();
return true;
}
return super.onOptionsItemSelected(item);
}
private void setPasswordStyle() {
TextView password = (TextView) findViewById(R.id.entry_password);
TextView confpassword = (TextView) findViewById(R.id.entry_confpassword);
if ( mShowPassword ) {
password.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD);
confpassword.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD);
} else {
password.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
confpassword.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD);
}
}
protected void fillData() {
ImageButton currIconButton = (ImageButton) findViewById(R.id.icon_button);
App.getDB().drawFactory.assignDrawableTo(currIconButton, getResources(), mEntry.getIcon());
populateText(R.id.entry_title, mEntry.getTitle());
populateText(R.id.entry_user_name, mEntry.getUsername());
populateText(R.id.entry_url, mEntry.getUrl());
String password = new String(mEntry.getPassword());
populateText(R.id.entry_password, password);
populateText(R.id.entry_confpassword, password);
setPasswordStyle();
populateText(R.id.entry_comment, mEntry.getNotes());
}
private void populateText(int viewId, String text) {
TextView tv = (TextView) findViewById(viewId);
tv.setText(text);
}
private final class AfterSave extends OnFinish {
public AfterSave(Handler handler) {
super(handler);
}
@Override
public void run() {
if ( mSuccess ) {
finish();
} else {
displayMessage(EntryEditActivity.this);
}
}
}
}