Implement Delete Groups and Entry. Refactor background code out of activities.

This commit is contained in:
Brian Pellin
2009-09-02 00:46:33 -05:00
parent abc50f7298
commit 8ef498338a
24 changed files with 697 additions and 244 deletions

BIN
assets/delete.kdb Normal file

Binary file not shown.

View File

@@ -23,6 +23,7 @@
<EditText android:id="@+id/group_name"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:hint="@string/hint_group_name"/>
<Button android:id="@+id/ok"
android:layout_width="100sp"
@@ -35,4 +36,4 @@
android:layout_below="@id/group_name"
android:layout_toRightOf="@id/ok"
android:text="@string/cancel"/>
</RelativeLayout>
</RelativeLayout>

View File

@@ -107,104 +107,6 @@ public class Database {
return searchHelper.search(this, str);
}
public void NewGroup(String name, PwGroup parent) throws PwManagerOutputException, IOException {
// Generate new group
PwGroup group = mPM.newGroup(name, parent);
// Commit to disk
try {
SaveData();
} catch (PwManagerOutputException e) {
mPM.removeGroup(group);
throw e;
} catch (IOException e) {
mPM.removeGroup(group);
throw e;
}
// Mark parent group dirty
gDirty.put(parent, new WeakReference<PwGroup>(parent));
// Add group to global list
gGroups.put(group.groupId, new WeakReference<PwGroup>(group));
}
public void NewEntry(PwEntry entry) throws IOException, PwManagerOutputException {
PwGroup parent = entry.parent;
// Add entry to group
parent.childEntries.add(entry);
// Add entry to PwManager
mPM.entries.add(entry);
// Commit to disk
try {
SaveData();
} catch (PwManagerOutputException e) {
UndoNewEntry(entry);
throw e;
} catch (IOException e) {
UndoNewEntry(entry);
throw e;
}
// Mark parent group dirty
gDirty.put(parent, new WeakReference<PwGroup>(parent));
// Add entry to global
gEntries.put(Types.bytestoUUID(entry.uuid), new WeakReference<PwEntry>(entry));
// Add entry to search index
searchHelper.insertEntry(entry);
}
public void UndoNewEntry(PwEntry entry) {
// Remove from group
entry.parent.childEntries.removeElement(entry);
// Remove from manager
mPM.entries.removeElement(entry);
}
public void UpdateEntry(PwEntry oldE, PwEntry newE) throws IOException, PwManagerOutputException {
// Keep backup of original values in case save fails
PwEntry backup = new PwEntry(oldE);
// Update entry with new values
oldE.assign(newE);
try {
SaveData();
} catch (PwManagerOutputException e) {
UndoUpdateEntry(oldE, backup);
throw e;
} catch (IOException e) {
UndoUpdateEntry(oldE, backup);
throw e;
}
// Mark group dirty if title changes
if ( ! oldE.title.equals(newE.title) ) {
PwGroup parent = oldE.parent;
if ( parent != null ) {
// Mark parent group dirty
gDirty.put(parent, new WeakReference<PwGroup>(parent));
}
}
// Update search index
searchHelper.updateEntry(oldE);
}
public void UndoUpdateEntry(PwEntry old, PwEntry backup) {
// If we fail to save, back out changes to global structure
old.assign(backup);
}
public void SaveData() throws IOException, PwManagerOutputException {
SaveData(mFilename);
}

View File

@@ -55,7 +55,7 @@ public class EntryActivity extends LockingActivity {
private static final int MENU_COPY_PASS = Menu.FIRST + 3;
private static final int MENU_LOCK = Menu.FIRST + 4;
private static final long CLIP_CLEAR_TIME = 300 * 1000;
private static final long CLIP_CLEAR_TIME = 5 * 60 * 1000;
public static void Launch(Activity act, PwEntry pw, int pos) {
Intent i = new Intent(act, EntryActivity.class);

View File

@@ -29,7 +29,6 @@ import org.phoneid.keepassj2me.PwGroup;
import org.phoneid.keepassj2me.Types;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
@@ -43,6 +42,8 @@ import android.widget.Toast;
import com.android.keepass.KeePass;
import com.android.keepass.R;
import com.keepassdroid.database.AddEntry;
import com.keepassdroid.database.UpdateEntry;
public class EntryEditActivity extends LockingActivity {
public static final String KEY_ENTRY = "entry";
@@ -53,7 +54,6 @@ public class EntryEditActivity extends LockingActivity {
private PwEntry mEntry;
private boolean mShowPassword = false;
private boolean mIsNew;
private ProgressDialog mPd;
public static void Launch(Activity act, PwEntry pw) {
Intent i = new Intent(act, EntryEditActivity.class);
@@ -165,11 +165,15 @@ public class EntryEditActivity extends LockingActivity {
} else {
setResult(KeePass.EXIT_REFRESH_TITLE);
}
mPd = ProgressDialog.show(EntryEditActivity.this, "Working...", "Saving database", true, false);
Thread bkgStore = new Thread(new BackgroundUpdateEntry(mEntry, newEntry));
bkgStore.start();
Runnable task;
if ( mIsNew ) {
task = new AddEntry(KeePass.db, act, newEntry, new Handler());
} else {
task = new UpdateEntry(KeePass.db, act, mEntry, newEntry, new Handler());
}
ProgressTask pt = new ProgressTask(act, task, act.new AfterSave());
pt.run();
}
});
@@ -248,46 +252,13 @@ public class EntryEditActivity extends LockingActivity {
tv.setText(text);
}
private final Handler uiHandler = new Handler();
private final class AfterSave implements Runnable {
@Override
public void run() {
mPd.dismiss();
finish();
}
}
private final class BackgroundUpdateEntry implements Runnable {
private final PwEntry mOld;
private final PwEntry mNew;
public BackgroundUpdateEntry(PwEntry oldE, PwEntry newE) {
mOld = oldE;
mNew = newE;
}
@Override
public void run() {
try {
if ( mIsNew ) {
KeePass.db.NewEntry(mNew);
} else {
KeePass.db.UpdateEntry(mOld, mNew);
}
uiHandler.post(new AfterSave());
} catch (Exception e) {
uiHandler.post(new UIToastTask(EntryEditActivity.this, "Failed to store database."));
mPd.dismiss();
setResult(KeePass.EXIT_NORMAL);
return;
}
}
}
}

View File

@@ -25,7 +25,6 @@ import org.phoneid.keepassj2me.PwGroup;
import android.app.Activity;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
@@ -39,6 +38,7 @@ import android.widget.AdapterView.AdapterContextMenuInfo;
import com.android.keepass.KeePass;
import com.android.keepass.R;
import com.keepassdroid.database.AddGroup;
public class GroupActivity extends GroupBaseActivity {
@@ -47,8 +47,6 @@ public class GroupActivity extends GroupBaseActivity {
public static final int ADD_GROUP_ONLY = 1;
public static final int FULL = 2;
private ProgressDialog mPd;
public static void Launch(Activity act, PwGroup group, int mode) {
Intent i = new Intent(act, GroupActivity.class);
@@ -160,9 +158,10 @@ public class GroupActivity extends GroupBaseActivity {
String res = mDialog.getResponse();
if ( ! mDialog.canceled() && res.length() > 0 ) {
mPd = ProgressDialog.show(GroupActivity.this, "Working...", "Saving database", true, false);
Thread bkgStore = new Thread(new BackgroundAddGroup(res, mGroup));
bkgStore.start();
GroupActivity act = GroupActivity.this;
AddGroup task = new AddGroup(KeePass.db, act, res, mGroup, new Handler(), false);
ProgressTask pt = new ProgressTask(act, task, act.new RefreshTask());
pt.run();
}
}
@@ -173,48 +172,5 @@ public class GroupActivity extends GroupBaseActivity {
}
}
private final Handler uiHandler = new Handler();
/** Task to be run after the database is saved in the UI thread
* @author Brian Pellin
*
*/
private final class AfterSave implements Runnable {
@Override
public void run() {
mPd.dismiss();
refreshIfDirty();
}
}
/** Handler storing the database in a separate thread
* @author Brian Pellin
*
*/
private final class BackgroundAddGroup implements Runnable {
private final String mName;
private final PwGroup mParent;
public BackgroundAddGroup(String name, PwGroup parent) {
mName = name;
mParent = parent;
}
@Override
public void run() {
try {
KeePass.db.NewGroup(mName, mParent);
uiHandler.post(new AfterSave());
} catch (Exception e) {
uiHandler.post(new UIToastTask(GroupActivity.this, R.string.error_could_not_create_group));
mPd.dismiss();
}
}
}
}

View File

@@ -31,6 +31,7 @@ import android.widget.BaseAdapter;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import com.android.keepass.KeePass;
import com.android.keepass.R;
@@ -61,13 +62,6 @@ public abstract class GroupBaseActivity extends LockingListActivity {
refreshIfDirty();
}
public class RefreshTask implements Runnable {
@Override
public void run() {
refreshIfDirty();
}
}
public void refreshIfDirty() {
if ( KeePass.db.gDirty.get(mGroup) != null ) {
KeePass.db.gDirty.remove(mGroup);
@@ -157,4 +151,27 @@ public abstract class GroupBaseActivity extends LockingListActivity {
return super.onOptionsItemSelected(item);
}
public class RefreshTask implements Runnable {
@Override
public void run() {
refreshIfDirty();
}
}
public class FatalError implements Runnable {
String mMsg;
public FatalError(String msg) {
mMsg = msg;
}
@Override
public void run() {
Toast.makeText(GroupBaseActivity.this, "Unrecoverable error: " + mMsg, Toast.LENGTH_LONG);
KeePass.db.shutdown = true;
finish();
}
}
}

View File

@@ -170,10 +170,12 @@ public class PasswordActivity extends Activity {
sendBroadcast(new Intent(TimeoutIntents.START));
}
/*
private void errorMessage(CharSequence text)
{
Toast.makeText(this, text, Toast.LENGTH_LONG).show();
}
*/
private void errorMessage(int resId)
{

View File

@@ -21,7 +21,7 @@ package com.keepassdroid;
import org.phoneid.keepassj2me.PwEntry;
import android.app.Activity;
import android.os.Handler;
import android.view.ContextMenu;
import android.view.Menu;
import android.view.MenuItem;
@@ -29,11 +29,13 @@ import android.view.View;
import android.view.ContextMenu.ContextMenuInfo;
import android.widget.TextView;
import com.android.keepass.KeePass;
import com.android.keepass.R;
import com.keepassdroid.database.DeleteEntry;
public class PwEntryView extends ClickView {
private Activity mAct;
private GroupBaseActivity mAct;
private PwEntry mPw;
private TextView mTv;
private int mPos;
@@ -41,7 +43,7 @@ public class PwEntryView extends ClickView {
private static final int MENU_EDIT = Menu.FIRST;
private static final int MENU_DELETE = Menu.FIRST + 1;
public PwEntryView(Activity act, PwEntry pw, int pos) {
public PwEntryView(GroupBaseActivity act, PwEntry pw, int pos) {
super(act);
mAct = act;
mPw = pw;
@@ -70,11 +72,18 @@ public class PwEntryView extends ClickView {
EntryActivity.Launch(mAct, mPw, mPos);
}
private void deleteEntry() {
DeleteEntry task = new DeleteEntry(KeePass.db, mPw, mAct, new Handler());
ProgressTask pt = new ProgressTask(mAct, task, mAct.new RefreshTask());
pt.run();
}
@Override
public void onCreateMenu(ContextMenu menu, ContextMenuInfo menuInfo) {
menu.add(0, MENU_EDIT, 0, R.string.menu_edit);
//menu.add(0, MENU_DELETE, 0, R.string.menu_delete);
menu.add(0, MENU_DELETE, 0, R.string.menu_delete);
}
@Override
@@ -85,6 +94,10 @@ public class PwEntryView extends ClickView {
launchEntry();
return true;
case MENU_DELETE:
deleteEntry();
return true;
default:
return false;
}

View File

@@ -69,8 +69,8 @@ public class PwGroupView extends ClickView {
@Override
public void onCreateMenu(ContextMenu menu, ContextMenuInfo menuInfo) {
menu.add(0, MENU_OPEN, 0, R.string.menu_open);
menu.add(0, MENU_DELETE, 0, R.string.menu_delete);
// TODO: Re-enable need to address entries and last group issue
//menu.add(0, MENU_DELETE, 0, R.string.menu_delete);
//menu.add(0, MENU_RENAME, 0, R.string.menu_rename);
}

View File

@@ -0,0 +1,88 @@
/*
* Copyright 2009 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.database;
import java.io.IOException;
import java.lang.ref.WeakReference;
import org.phoneid.keepassj2me.PwEntry;
import org.phoneid.keepassj2me.PwGroup;
import org.phoneid.keepassj2me.Types;
import android.content.Context;
import android.os.Handler;
import com.keepassdroid.Database;
import com.keepassdroid.UIToastTask;
import com.keepassdroid.keepasslib.PwManagerOutputException;
public class AddEntry implements Runnable {
private Database mDb;
private Context mCtx;
private PwEntry mEntry;
private Handler mHandler;
public AddEntry(Database db, Context ctx, PwEntry entry, Handler handler) {
mDb = db;
mCtx = ctx;
mEntry = entry;
mHandler = handler;
}
@Override
public void run() {
PwGroup parent = mEntry.parent;
// Add entry to group
parent.childEntries.add(mEntry);
// Add entry to PwManager
mDb.mPM.entries.add(mEntry);
// Commit to disk
try {
mDb.SaveData();
} catch (PwManagerOutputException e) {
undoNewEntry(mEntry);
mHandler.post(new UIToastTask(mCtx, "Failed to store database."));
} catch (IOException e) {
undoNewEntry(mEntry);
mHandler.post(new UIToastTask(mCtx, "Failed to store database."));
}
// Mark parent group dirty
mDb.gDirty.put(parent, new WeakReference<PwGroup>(parent));
// Add entry to global
mDb.gEntries.put(Types.bytestoUUID(mEntry.uuid), new WeakReference<PwEntry>(mEntry));
// Add entry to search index
mDb.searchHelper.insertEntry(mEntry);
}
private void undoNewEntry(PwEntry entry) {
// Remove from group
entry.parent.childEntries.removeElement(entry);
// Remove from manager
mDb.mPM.entries.removeElement(entry);
}
}

View File

@@ -0,0 +1,83 @@
/*
* Copyright 2009 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.database;
import java.io.IOException;
import java.lang.ref.WeakReference;
import org.phoneid.keepassj2me.PwGroup;
import org.phoneid.keepassj2me.PwManager;
import android.content.Context;
import android.os.Handler;
import com.android.keepass.R;
import com.keepassdroid.Database;
import com.keepassdroid.UIToastTask;
import com.keepassdroid.keepasslib.PwManagerOutputException;
public class AddGroup implements Runnable {
private Database mDb;
private String mName;
private PwGroup mParent;
private Handler mHandler;
private Context mCtx;
private boolean mNoSave;
public AddGroup(Database db, Context ctx, String name, PwGroup parent, Handler handler, boolean noSave) {
mDb = db;
mCtx = ctx;
mName = name;
mParent = parent;
mHandler = handler;
mNoSave = noSave;
}
@Override
public void run() {
PwManager pm = mDb.mPM;
// Generate new group
PwGroup group = pm.newGroup(mName, mParent);
// Commit to disk
if ( ! mNoSave ) {
try {
mDb.SaveData();
} catch (PwManagerOutputException e) {
pm.removeGroup(group);
mHandler.post(new UIToastTask(mCtx, R.string.error_could_not_create_group));
return;
} catch (IOException e) {
pm.removeGroup(group);
mHandler.post(new UIToastTask(mCtx, R.string.error_could_not_create_group));
return;
}
}
// Mark parent group dirty
mDb.gDirty.put(mParent, new WeakReference<PwGroup>(mParent));
// Add group to global list
mDb.gGroups.put(group.groupId, new WeakReference<PwGroup>(group));
}
}

View File

@@ -0,0 +1,132 @@
/*
* Copyright 2009 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.database;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.Vector;
import org.phoneid.keepassj2me.PwEntry;
import org.phoneid.keepassj2me.PwGroup;
import android.content.Context;
import android.os.Handler;
import com.keepassdroid.Database;
import com.keepassdroid.UIToastTask;
import com.keepassdroid.keepasslib.PwManagerOutputException;
import com.keepassdroid.search.SearchDbHelper;
/** Task to delete entries
* @author bpellin
*
*/
public class DeleteEntry implements Runnable {
private Database mDb;
private Vector<PwEntry> mEntries;
private Context mCtx;
private Handler mHandler;
private boolean mDontSave;
public DeleteEntry(Database db, PwEntry entry, Context ctx, Handler handler) {
Vector<PwEntry> entries = new Vector<PwEntry>();
entries.add(entry);
setMembers(db, entries, ctx, handler, false);
}
public DeleteEntry(Database db, Vector<PwEntry> entries, Context ctx, Handler handler, boolean dontSave) {
setMembers(db, entries, ctx, handler, dontSave);
}
@SuppressWarnings("unchecked")
private void setMembers(Database db, Vector<PwEntry> entries, Context ctx, Handler handler, boolean dontSave) {
mDb = db;
mEntries = (Vector<PwEntry>) entries.clone();
mCtx = ctx;
mHandler = handler;
mDontSave = dontSave;
}
@Override
public void run() {
SearchDbHelper dbHelper = new SearchDbHelper(mCtx);
dbHelper.open();
for ( int i = 0; i < mEntries.size(); i++ ) {
PwEntry entry = mEntries.get(i);
if ( entry != null ) {
removeEntry(entry, dbHelper);
}
}
dbHelper.close();
}
private void removeEntry(PwEntry entry, SearchDbHelper dbHelper) {
// Remove Entry from parent
PwGroup parent = entry.parent;
parent.childEntries.remove(entry);
// Remove Entry from PwManager
mDb.mPM.entries.remove(entry);
// Save
if ( ! mDontSave ) {
try {
mDb.SaveData();
} catch (IOException e) {
saveError(entry, e.getMessage());
return;
} catch (PwManagerOutputException e) {
saveError(entry, e.getMessage());
return;
}
}
// Remove from entry global
mDb.gEntries.remove(entry);
// Remove from search db
dbHelper.deleteEntry(entry);
// Mark parent dirty
if ( parent != null ) {
mDb.gDirty.put(parent, new WeakReference<PwGroup>(parent));
}
}
private void saveError(PwEntry entry, String msg) {
undoRemoveEntry(entry);
mHandler.post(new UIToastTask(mCtx, msg));
}
private void undoRemoveEntry(PwEntry entry) {
mDb.mPM.entries.add(entry);
PwGroup parent = entry.parent;
if ( parent != null ) {
parent.childEntries.add(entry);
}
}
}

View File

@@ -1,33 +1,92 @@
/*
* Copyright 2009 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.database;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.Vector;
import org.phoneid.keepassj2me.PwEntry;
import org.phoneid.keepassj2me.PwGroup;
import android.content.Context;
import android.os.Handler;
import com.keepassdroid.Database;
import com.keepassdroid.UIToastTask;
import com.keepassdroid.GroupBaseActivity;
import com.keepassdroid.keepasslib.PwManagerOutputException;
public class DeleteGroup implements Runnable {
private Database mDb;
private PwGroup mGroup;
private Handler uiHandler;
private Handler mHandler;
private GroupBaseActivity mAct;
private Context mCtx;
private boolean mDontSave;
public DeleteGroup(Database db, PwGroup group, Context ctx, Handler handler) {
public DeleteGroup(Database db, PwGroup group, GroupBaseActivity act, Handler handler) {
setMembers(db, group, act, act, handler, false);
}
public DeleteGroup(Database db, PwGroup group, GroupBaseActivity act, Handler handler, boolean dontSave) {
setMembers(db, group, act, act, handler, dontSave);
}
public DeleteGroup(Database db, PwGroup group, GroupBaseActivity act, Context ctx, Handler handler, boolean dontSave) {
setMembers(db, group, act, ctx, handler, dontSave);
}
public DeleteGroup(Database db, PwGroup group, Context ctx, Handler handler, boolean dontSave) {
setMembers(db, group, null, ctx, handler, dontSave);
}
private void setMembers(Database db, PwGroup group, GroupBaseActivity act, Context ctx, Handler handler, boolean dontSave) {
mDb = db;
mGroup = group;
uiHandler = handler;
mHandler = handler;
mAct = act;
mCtx = ctx;
mDontSave = dontSave;
}
@Override
public void run() {
// Remove child entries
Vector<PwEntry> childEnt = mGroup.childEntries;
if ( childEnt.size() > 0 ) {
DeleteEntry task = new DeleteEntry(mDb, childEnt, mCtx, mHandler, true);
task.run();
}
// Remove child groups
Vector<PwGroup> childGrp = mGroup.childGroups;
for ( int i = 0; i < childGrp.size(); i++ ) {
DeleteGroup task = new DeleteGroup(mDb, childGrp.get(i), mAct, mCtx, mHandler, true);
task.run();
}
// Remove from parent
PwGroup parent = mGroup.parent;
if ( parent != null ) {
@@ -38,36 +97,40 @@ public class DeleteGroup implements Runnable {
mDb.mPM.groups.remove(mGroup);
// Save
try {
mDb.SaveData();
} catch (IOException e) {
saveError(e.getMessage());
return;
} catch (PwManagerOutputException e) {
saveError(e.getMessage());
return;
if ( ! mDontSave ) {
try {
mDb.SaveData();
} catch (IOException e) {
saveError(e.getMessage());
return;
} catch (PwManagerOutputException e) {
saveError(e.getMessage());
return;
}
}
// Remove from group global
mDb.gGroups.remove(mGroup.groupId);
// Remove group from the dirty global (if it is present), not a big deal if this fails
try {
mDb.gDirty.remove(mGroup);
} catch ( Exception e) {
// Suppress
}
// Mark parent dirty
mDb.gDirty.put(parent, new WeakReference<PwGroup>(mGroup));
if ( parent != null ) {
mDb.gDirty.put(parent, new WeakReference<PwGroup>(parent));
}
}
private void saveError(String msg) {
undoRemoveGroup();
uiHandler.post(new UIToastTask(mCtx, msg));
// Let's not bother recovering from a failure to save a deleted group. It is too much work.
if ( mAct != null ) {
mHandler.post(mAct.new FatalError(msg));
}
}
private void undoRemoveGroup() {
mDb.mPM.groups.add(mGroup);
PwGroup parent = mGroup.parent;
if ( parent != null ) {
parent.childGroups.add(mGroup);
}
}
}

View File

@@ -0,0 +1,86 @@
/*
* Copyright 2009 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.database;
import java.io.IOException;
import java.lang.ref.WeakReference;
import org.phoneid.keepassj2me.PwEntry;
import org.phoneid.keepassj2me.PwGroup;
import android.content.Context;
import android.os.Handler;
import com.keepassdroid.Database;
import com.keepassdroid.UIToastTask;
import com.keepassdroid.keepasslib.PwManagerOutputException;
public class UpdateEntry implements Runnable {
private Database mDb;
private Context mCtx;
private PwEntry mOldE;
private PwEntry mNewE;
private Handler mHandler;
public UpdateEntry(Database db, Context ctx, PwEntry oldE, PwEntry newE, Handler handler) {
mDb = db;
mCtx = ctx;
mOldE = oldE;
mNewE = newE;
mHandler = handler;
}
@Override
public void run() {
// Keep backup of original values in case save fails
PwEntry backup = new PwEntry(mOldE);
// Update entry with new values
mOldE.assign(mNewE);
try {
mDb.SaveData();
} catch (PwManagerOutputException e) {
undoUpdateEntry(mOldE, backup);
mHandler.post(new UIToastTask(mCtx, "Failed to store database."));
} catch (IOException e) {
undoUpdateEntry(mOldE, backup);
mHandler.post(new UIToastTask(mCtx, "Failed to store database."));
}
// Mark group dirty if title changes
if ( ! mOldE.title.equals(mNewE.title) ) {
PwGroup parent = mOldE.parent;
if ( parent != null ) {
// Mark parent group dirty
mDb.gDirty.put(parent, new WeakReference<PwGroup>(parent));
}
}
// Update search index
mDb.searchHelper.updateEntry(mOldE);
}
private void undoUpdateEntry(PwEntry old, PwEntry backup) {
// If we fail to save, back out changes to global structure
old.assign(backup);
}
}

View File

@@ -76,6 +76,9 @@ public class PwManagerOutput {
public void output() throws PwManagerOutputException {
// Before we output the header, we should sort our list of groups and remove any orphaned nodes that are no longer part of the group hierarchy
sortGroupsForOutput();
PwDbHeader header = outputHeader(mOS);
byte[] finalKey = getFinalKey(header);
@@ -174,9 +177,14 @@ public class PwManagerOutput {
//long size = 0;
// Groups
Vector<PwGroup> roots = mPM.getGrpRoots();
for (int i = 0; i < roots.size(); i++ ) {
outputGroups(os, roots.get(i));
for ( int i = 0; i < mPM.groups.size(); i++ ) {
PwGroup pg = mPM.groups.get(i);
PwGroupOutput pgo = new PwGroupOutput(pg, os);
try {
pgo.output();
} catch (IOException e) {
throw new PwManagerOutputException("Failed to output a group: " + e.getMessage());
}
}
// Entries
@@ -191,18 +199,25 @@ public class PwManagerOutput {
}
}
public void outputGroups(OutputStream os, PwGroup group) throws PwManagerOutputException {
// Output the current group
PwGroupOutput pgo = new PwGroupOutput(group, os);
try {
pgo.output();
} catch (IOException e) {
throw new PwManagerOutputException("Failed to output a group: " + e.getMessage());
private void sortGroupsForOutput() {
Vector<PwGroup> groupList = new Vector<PwGroup>();
// Rebuild list according to coalation sorting order removing any orphaned groups
Vector<PwGroup> roots = mPM.getGrpRoots();
for ( int i = 0; i < roots.size(); i++ ) {
sortGroup(roots.get(i), groupList);
}
// Output the child groups
mPM.groups = groupList;
}
private void sortGroup(PwGroup group, Vector<PwGroup> groupList) {
// Add current group
groupList.add(group);
// Recurse over children
for ( int i = 0; i < group.childGroups.size(); i++ ) {
outputGroups(os, group.childGroups.get(i));
sortGroup(group.childGroups.get(i), groupList);
}
}
}

View File

@@ -118,9 +118,14 @@ public class SearchDbHelper {
ContentValues cv = buildNewEntryContent(entry);
String uuidStr = cv.getAsString(KEY_UUID);
mDb.update(SEARCH_TABLE, cv, KEY_UUID + "= ?", new String[] {uuidStr});
mDb.update(SEARCH_TABLE, cv, KEY_UUID + " = ?", new String[] {uuidStr});
}
public void deleteEntry(PwEntry entry) {
UUID uuid = Types.bytestoUUID(entry.uuid);
String uuidStr = uuid.toString();
mDb.delete(SEARCH_TABLE, KEY_UUID + " = ?", new String[] {uuidStr});
}
public PwGroup search(Database db, String qStr) {

View File

@@ -21,7 +21,7 @@ package com.keepassdroid.tests;
import android.test.AndroidTestCase;
import com.keepassdroid.tests.output.TestData;
import com.keepassdroid.tests.database.TestData;
public class AccentTest extends AndroidTestCase {

View File

@@ -28,7 +28,7 @@ import org.phoneid.keepassj2me.PwEntry;
import android.test.AndroidTestCase;
import com.keepassdroid.tests.output.TestData;
import com.keepassdroid.tests.database.TestData;
public class PwEntryTest extends AndroidTestCase {
PwEntry mPE;

View File

@@ -23,7 +23,7 @@ import org.phoneid.keepassj2me.PwGroup;
import android.test.AndroidTestCase;
import com.keepassdroid.tests.output.TestData;
import com.keepassdroid.tests.database.TestData;
public class PwGroupTest extends AndroidTestCase {

View File

@@ -0,0 +1,117 @@
/*
* Copyright 2009 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 3 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.tests.database;
import java.util.Vector;
import org.phoneid.keepassj2me.PwEntry;
import org.phoneid.keepassj2me.PwGroup;
import org.phoneid.keepassj2me.PwManager;
import android.content.Context;
import android.os.Handler;
import android.test.AndroidTestCase;
import com.keepassdroid.Database;
import com.keepassdroid.database.DeleteGroup;
import com.keepassdroid.search.SearchDbHelper;
public class DeleteEntry extends AndroidTestCase {
private static final String GROUP1_NAME = "Group1";
private static final String ENTRY1_NAME = "Test1";
private static final String ENTRY2_NAME = "Test2";
private static final String KEYFILE = "";
private static final String PASSWORD = "12345";
private static final String ASSET = "delete.kdb";
private static final String FILENAME = "/sdcard/delete.kdb";
public void testDelete() {
Database db;
Context ctx = getContext();
try {
db = TestData.GetDb(ctx, ASSET, PASSWORD, KEYFILE, FILENAME);
} catch (Exception e) {
assertTrue("Failed to open database: " + e.getMessage(), false);
return;
}
PwGroup group1 = getGroup(db.mPM, GROUP1_NAME);
assertNotNull("Could not find group1", group1);
// Delete the group
DeleteGroup task = new DeleteGroup(db, group1, ctx, new Handler(), true);
task.run();
// Verify the entries were deleted
PwEntry entry1 = getEntry(db.mPM, ENTRY1_NAME);
assertNull("Entry 1 was not removed", entry1);
PwEntry entry2 = getEntry(db.mPM, ENTRY2_NAME);
assertNull("Entry 2 was not removed", entry2);
// Verify the entries were removed from the search index
SearchDbHelper dbHelp = new SearchDbHelper(ctx);
dbHelp.open();
PwGroup results1 = dbHelp.search(db, ENTRY1_NAME);
PwGroup results2 = dbHelp.search(db, ENTRY2_NAME);
dbHelp.close();
assertEquals("Entry1 was not removed from the search results", 0, results1.childEntries.size());
assertEquals("Entry2 was not removed from the search results", 0, results2.childEntries.size());
// Verify the group was deleted
group1 = getGroup(db.mPM, GROUP1_NAME);
assertNull("Group 1 was not removed.", group1);
}
private PwEntry getEntry(PwManager pm, String name) {
Vector<PwEntry> entries = pm.entries;
for ( int i = 0; i < entries.size(); i++ ) {
PwEntry entry = entries.get(i);
if ( entry.title.equals(name) ) {
return entry;
}
}
return null;
}
private PwGroup getGroup(PwManager pm, String name) {
Vector<PwGroup> groups = pm.groups;
for ( int i = 0; i < groups.size(); i++ ) {
PwGroup group = groups.get(i);
if ( group.name.equals(name) ) {
return group;
}
}
return null;
}
}

View File

@@ -17,7 +17,7 @@
* along with KeePassDroid. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.keepassdroid.tests.output;
package com.keepassdroid.tests.database;
import java.io.IOException;
import java.io.InputStream;

View File

@@ -39,6 +39,7 @@ import com.keepassdroid.keepasslib.NullOutputStream;
import com.keepassdroid.keepasslib.PwDbHeaderOutput;
import com.keepassdroid.keepasslib.PwManagerOutput;
import com.keepassdroid.keepasslib.PwManagerOutputException;
import com.keepassdroid.tests.database.TestData;
public class PwManagerOutputTest extends AndroidTestCase {
PwManager mPM;

View File

@@ -24,7 +24,7 @@ import org.phoneid.keepassj2me.PwGroup;
import android.test.AndroidTestCase;
import com.keepassdroid.Database;
import com.keepassdroid.tests.output.TestData;
import com.keepassdroid.tests.database.TestData;
public class SearchTest extends AndroidTestCase {
@@ -38,6 +38,7 @@ public class SearchTest extends AndroidTestCase {
}
public void testSearch() {
PwGroup results = mDb.Search("Amazon");
assertTrue("Search result not found.", results.childEntries.size() > 0);