Implement add group. Still need to move it to the backgroud.

This commit is contained in:
Brian Pellin
2009-07-16 13:28:08 -05:00
parent 7713ac01ac
commit be3e47a6f8
13 changed files with 374 additions and 34 deletions

View File

@@ -18,12 +18,6 @@
<!-- whenever the user invokes search while in this Activity. -->
<meta-data android:name="android.app.default_searchable"
android:value=".search.SearchResults" />
</activity>
<activity android:name=".GroupAddEntryActivity">
<!-- This metadata entry causes .app.SearchQueryResults to be the default context -->
<!-- whenever the user invokes search while in this Activity. -->
<meta-data android:name="android.app.default_searchable"
android:value=".search.SearchResults" />
</activity>
<activity android:name=".EntryActivity"></activity>
<activity android:name=".LockingActivity"></activity>

View File

@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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/>.
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<EditText android:id="@+id/group_name"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:hint="@string/hint_group_name"/>
<Button android:id="@+id/ok"
android:layout_width="100sp"
android:layout_height="wrap_content"
android:layout_below="@id/group_name"
android:text="@string/pass_ok"/>
<Button android:id="@+id/cancel"
android:layout_width="100sp"
android:layout_height="wrap_content"
android:layout_below="@id/group_name"
android:layout_toRightOf="@id/ok"
android:text="@string/cancel"/>
</RelativeLayout>

View File

@@ -43,9 +43,15 @@
android:scaleType="fitXY"
android:tint="@color/blue_highlight"
android:src="@android:drawable/divider_horizontal_dark"/>
<Button android:id="@+id/add_group"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:text="@string/add_group"/>
<Button android:id="@+id/add_entry"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/add_group"
android:layout_alignParentBottom="true"
android:text="@string/add_entry"/>
<ImageView android:id="@+id/divider2"

63
res/layout/group_root.xml Normal file
View File

@@ -0,0 +1,63 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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/>.
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView android:id="@+id/group_header"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="15sp"
android:text="@string/current_group"
android:textStyle="bold"
android:layout_weight="0"/>
<TextView android:id="@+id/group_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignTop="@id/group_header"
android:layout_toRightOf="@id/group_header"
android:layout_marginLeft="3sp"
android:text="@string/root"
style="@style/GroupTextSmall"
android:layout_weight="0"/>
<ImageView android:id="@+id/divider1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_below="@id/group_header"
android:scaleType="fitXY"
android:tint="@color/blue_highlight"
android:src="@android:drawable/divider_horizontal_dark"/>
<Button android:id="@+id/add_group"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:text="@string/add_group"/>
<ImageView android:id="@+id/divider2"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_above="@id/add_group"
android:scaleType="fitXY"
android:tint="@color/blue_highlight"
android:src="@android:drawable/divider_horizontal_dark"/>
<ListView android:id="@android:id/list"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_above="@id/divider2"
android:layout_below="@id/divider1"/>
</RelativeLayout>

View File

@@ -1,10 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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/>.
-->
<resources>
<string name="app_name">KeePassDroid</string>
<string name="no_keys">No entries in the database or group.</string>
<string name="FileNotFound">File not found.</string>
<string name="InvalidPassword">Invalid password or key file.</string>
<string name="pass_ok">Ok</string>
<string name="cancel">Cancel</string>
<string name="entry_title">Name: </string>
<string name="entry_user_name">User Name: </string>
<string name="entry_url">URL: </string>
@@ -44,7 +63,10 @@
<string name="entry_confpassword">Confirm password:</string>
<string name="disclaimer_formal">KeePassDroid Copyright 2009 Brian Pellin comes with ABSOLUTELY NO WARRANTY; This is free software, and you are welcome to redistribute it under the conditions of the GPL version 2 or later.</string>
<string name="add_entry">Add Entry</string>
<string name="add_group_title">Add Group</string>
<string name="hint_group_name">Group name</string>
<string name="add_group">Add group</string>
<string name="add_entry">Add entry</string>
<string name="error_pass_match">Passwords do not match.</string>
<string name="error_title_required">A title is required.</string>
<string name="menu_search">Search</string>
@@ -58,4 +80,6 @@
<string name="hint_conf_pass">confirm password</string>
<string name="hint_comment">comment</string>
<string name="no_url_handler">No handler for this url.</string>
<string name="error_no_name">A name is required.</string>
<string name="error_could_not_create_group">Error creating group.</string>
</resources>

View File

@@ -106,6 +106,29 @@ 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;

View File

@@ -19,21 +19,62 @@
*/
package com.android.keepass;
import java.io.IOException;
import java.lang.ref.WeakReference;
import org.phoneid.keepassj2me.PwGroup;
import android.app.Activity;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import com.android.keepass.keepasslib.PwManagerOutputException;
public class GroupActivity extends GroupBaseActivity {
public static final int UNINIT = -1;
public static final int VIEW_ONLY = 0;
public static final int ADD_GROUP_ONLY = 1;
public static final int FULL = 2;
public static void Launch(Activity act, PwGroup group, int mode) {
Intent i = new Intent(act, GroupActivity.class);
if ( group != null ) {
i.putExtra(KEY_ENTRY, group.groupId);
}
i.putExtra(KEY_MODE, mode);
act.startActivityForResult(i,0);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.group_view_only);
setResult(KeePass.EXIT_NORMAL);
Intent intent = getIntent();
int id = getIntent().getIntExtra(KEY_ENTRY, -1);
int mode = intent.getIntExtra(KEY_MODE, UNINIT);
switch ( mode ) {
case FULL:
setContentView(R.layout.group_add_entry);
break;
case ADD_GROUP_ONLY:
setContentView(R.layout.group_root);
break;
default:
setContentView(R.layout.group_view_only);
}
int id = intent.getIntExtra(KEY_ENTRY, -1);
if ( id == -1 ) {
mGroup = KeePass.db.gRoot;
@@ -43,8 +84,69 @@ public class GroupActivity extends GroupBaseActivity {
}
assert(mGroup != null);
if ( mode == FULL || mode == ADD_GROUP_ONLY ) {
// Add Group button
Button addGroup = (Button) findViewById(R.id.add_group);
addGroup.setOnClickListener(new GroupAddHandler(this, mGroup));
}
if ( mode == FULL ) {
// Add Entry button
Button addEntry = (Button) findViewById(R.id.add_entry);
addEntry.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
EntryEditActivity.Launch(GroupActivity.this, mGroup);
}
});
}
setGroupTitle();
setListAdapter(new PwListAdapter(this, mGroup));
}
private class GroupAddHandler implements View.OnClickListener {
private GroupBaseActivity mAct;
private PwGroup mGroup;
private GroupCreateDialog mDialog;
GroupAddHandler(GroupBaseActivity act, PwGroup group) {
mAct = act;
mGroup = group;
}
@Override
public void onClick(View v) {
GroupCreateDialog dialog = new GroupCreateDialog(mAct);
mDialog = dialog;
// Register Listener
dialog.setOnDismissListener(new Dialog.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
String res = mDialog.getResponse();
try {
KeePass.db.NewGroup(res, mGroup);
} catch (PwManagerOutputException e) {
Toast.makeText(mAct, R.string.error_could_not_create_group, Toast.LENGTH_LONG).show();
return;
} catch (IOException e) {
Toast.makeText(mAct, R.string.error_could_not_create_group, Toast.LENGTH_LONG).show();
return;
}
mAct.refreshIfDirty();
}
});
dialog.show();
}
}
}

View File

@@ -34,6 +34,7 @@ import android.widget.TextView;
public abstract class GroupBaseActivity extends LockingListActivity {
public static final String KEY_ENTRY = "entry";
public static final String KEY_MODE = "mode";
protected static final int MENU_LOCK = Menu.FIRST;
protected static final int MENU_SEARCH = Menu.FIRST + 1;
@@ -54,6 +55,10 @@ public abstract class GroupBaseActivity extends LockingListActivity {
protected void onResume() {
super.onResume();
refreshIfDirty();
}
public void refreshIfDirty() {
if ( KeePass.db.gDirty.get(mGroup) != null ) {
KeePass.db.gDirty.remove(mGroup);
BaseAdapter adapter = (BaseAdapter) getListAdapter();

View File

@@ -19,43 +19,56 @@
*/
package com.android.keepass;
import org.phoneid.keepassj2me.PwGroup;
import android.app.Activity;
import android.content.Intent;
import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
public class GroupAddEntryActivity extends GroupActivity {
public static void Launch(Activity act, PwGroup group) {
Intent i = new Intent(act, GroupAddEntryActivity.class);
public class GroupCreateDialog extends Dialog {
Context mCtx;
String mRes;
public GroupCreateDialog(Context context) {
super(context);
i.putExtra(KEY_ENTRY, group.groupId);
act.startActivityForResult(i,0);
mCtx = context;
}
public String getResponse() {
return mRes;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.group_add_entry);
styleScrollBars();
setContentView(R.layout.create_group);
setTitle(R.string.add_group_title);
// Add Entry button
Button addEntry = (Button) findViewById(R.id.add_entry);
addEntry.setOnClickListener(new View.OnClickListener() {
@Override
Button okButton = (Button) findViewById(R.id.ok);
okButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
EntryEditActivity.Launch(GroupAddEntryActivity.this, mGroup);
TextView nameField = (TextView) findViewById(R.id.group_name);
String name = nameField.getText().toString();
if ( name.length() > 0 ) {
mRes = name;
dismiss();
} else {
Toast.makeText(mCtx, R.string.error_no_name, Toast.LENGTH_LONG).show();
}
}
});
setGroupTitle();
Button cancel = (Button) findViewById(R.id.cancel);
cancel.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
dismiss();
}
});
}
}

View File

@@ -232,7 +232,7 @@ public class PasswordActivity extends Activity {
}
if ( mLaunch ) {
GroupActivity.Launch(PasswordActivity.this, null);
GroupActivity.Launch(PasswordActivity.this, null, GroupActivity.ADD_GROUP_ONLY);
}
}
}

View File

@@ -48,7 +48,7 @@ public class PwGroupView extends ClickView {
void onClick() {
GroupAddEntryActivity.Launch(mAct, mPw);
GroupActivity.Launch(mAct, mPw, GroupActivity.FULL);
}

View File

@@ -47,6 +47,8 @@ public class PwGroup {
public String toString() {
return name;
}
public static final Date NEVER_EXPIRE = PwEntry.NEVER_EXPIRE;
/** Size of byte buffer needed to hold this struct. */
public static final int BUF_SIZE = 124;

View File

@@ -31,6 +31,9 @@ import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Calendar;
import java.util.Date;
import java.util.Random;
import java.util.Vector;
import org.bouncycastle.crypto.digests.SHA256Digest;
@@ -296,6 +299,7 @@ public class PwManager {
Vector<PwGroup> rootChildGroups = getGrpRoots();
rootGroup.childGroups = rootChildGroups;
rootGroup.childEntries = new Vector<PwEntry>();
rootGroup.level = -1;
for (int i=0; i<rootChildGroups.size(); i++) {
rootChildGroups.elementAt(i).parent = rootGroup;
constructTree(rootChildGroups.elementAt(i));
@@ -319,4 +323,70 @@ public class PwManager {
}
return;
}
public PwGroup newGroup(String name, PwGroup parent) {
// Initialize group
PwGroup group = new PwGroup();
group.parent = parent;
group.groupId = newGroupId();
group.imageId = 0;
group.name = name;
Date now = Calendar.getInstance().getTime();
group.tCreation = now;
group.tLastAccess = now;
group.tLastMod = now;
group.tExpire = PwGroup.NEVER_EXPIRE;
group.level = parent.level + 1;
group.childEntries = new Vector<PwEntry>();
group.childGroups = new Vector<PwGroup>();
// Add group PwManager and Parent
parent.childGroups.add(group);
groups.add(group);
return group;
}
public void removeGroup(PwGroup group) {
group.parent.childGroups.remove(group);
groups.remove(group);
}
/** Generates an unused random group id
* @return new group id
*/
private int newGroupId() {
boolean foundUnusedId = false;
int newId = 0;
Random random = new Random();
while ( ! foundUnusedId ) {
newId = random.nextInt();
if ( ! isGroupIdUsed(newId) ) {
foundUnusedId = true;
}
}
return newId;
}
/** Determine if an id number is already in use
* @param id ID number to check for
* @return True if the ID is used, false otherwise
*/
private boolean isGroupIdUsed(int id) {
for ( int i = 0; i < groups.size(); i++ ) {
if ( groups.get(i).groupId == id ) {
return true;
}
}
return false;
}
}