diff --git a/app/src/androidTest/java/com/kunzisoft/keepass/tests/database/DeleteEntry.java b/app/src/androidTest/java/com/kunzisoft/keepass/tests/database/DeleteEntry.java
index 15f06fdb0..88597ae20 100644
--- a/app/src/androidTest/java/com/kunzisoft/keepass/tests/database/DeleteEntry.java
+++ b/app/src/androidTest/java/com/kunzisoft/keepass/tests/database/DeleteEntry.java
@@ -29,7 +29,7 @@ import com.kunzisoft.keepass.database.PwEntry;
import com.kunzisoft.keepass.database.PwEntryV3;
import com.kunzisoft.keepass.database.PwGroup;
import com.kunzisoft.keepass.database.action.node.DeleteGroupRunnable;
-import com.kunzisoft.keepass.search.SearchDbHelper;
+import com.kunzisoft.keepass.database.search.SearchDbHelper;
import java.util.List;
@@ -72,8 +72,8 @@ public class DeleteEntry extends AndroidTestCase {
// Verify the entries were removed from the search index
SearchDbHelper dbHelp = new SearchDbHelper(ctx);
- PwGroup results1 = dbHelp.search(db.getPwDatabase(), ENTRY1_NAME);
- PwGroup results2 = dbHelp.search(db.getPwDatabase(), ENTRY2_NAME);
+ PwGroup results1 = dbHelp.search(db.getPwDatabase(), ENTRY1_NAME, 100);
+ PwGroup results2 = dbHelp.search(db.getPwDatabase(), ENTRY2_NAME, 100);
assertEquals("Entry1 was not removed from the search results", 0, results1.numbersOfChildEntries());
assertEquals("Entry2 was not removed from the search results", 0, results2.numbersOfChildEntries());
diff --git a/app/src/androidTest/java/com/kunzisoft/keepass/tests/database/EntryV4.java b/app/src/androidTest/java/com/kunzisoft/keepass/tests/database/EntryV4.java
index c4a7f4cea..b20fa9b32 100644
--- a/app/src/androidTest/java/com/kunzisoft/keepass/tests/database/EntryV4.java
+++ b/app/src/androidTest/java/com/kunzisoft/keepass/tests/database/EntryV4.java
@@ -19,11 +19,11 @@
*/
package com.kunzisoft.keepass.tests.database;
-import junit.framework.TestCase;
-
import com.kunzisoft.keepass.database.PwDatabaseV4;
import com.kunzisoft.keepass.database.PwEntryV4;
+import junit.framework.TestCase;
+
public class EntryV4 extends TestCase {
public void testBackup() {
@@ -46,7 +46,7 @@ public class EntryV4 extends TestCase {
entry.createBackup(db);
PwEntryV4 backup = entry.getHistory().get(0);
- entry.endToManageFieldReferences();
+ entry.stopToManageFieldReferences();
assertEquals("Title2", backup.getTitle());
assertEquals("User2", backup.getUsername());
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 0aca145fd..36986775d 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -104,11 +104,19 @@
+ android:windowSoftInputMode="adjustPan"
+ android:launchMode="singleTop">
+
+
+
+
+
-
-
-
-
-
-
-
diff --git a/app/src/main/java/com/kunzisoft/keepass/activities/EntryActivity.java b/app/src/main/java/com/kunzisoft/keepass/activities/EntryActivity.java
index ebb6a7ff2..b992ab77a 100644
--- a/app/src/main/java/com/kunzisoft/keepass/activities/EntryActivity.java
+++ b/app/src/main/java/com/kunzisoft/keepass/activities/EntryActivity.java
@@ -225,7 +225,7 @@ public class EntryActivity extends LockingHideActivity {
startService(intent);
}
- mEntry.endToManageFieldReferences();
+ mEntry.stopToManageFieldReferences();
}
firstLaunchOfActivity = false;
}
@@ -369,7 +369,7 @@ public class EntryActivity extends LockingHideActivity {
entryContentsView.assignExpiresDate(getString(R.string.never));
}
- mEntry.endToManageFieldReferences();
+ mEntry.stopToManageFieldReferences();
}
@Override
diff --git a/app/src/main/java/com/kunzisoft/keepass/activities/EntryEditActivity.java b/app/src/main/java/com/kunzisoft/keepass/activities/EntryEditActivity.java
index 08a8512b8..d470c2685 100644
--- a/app/src/main/java/com/kunzisoft/keepass/activities/EntryEditActivity.java
+++ b/app/src/main/java/com/kunzisoft/keepass/activities/EntryEditActivity.java
@@ -429,7 +429,7 @@ public class EntryEditActivity extends LockingHideActivity
}
}
- newEntry.endToManageFieldReferences();
+ newEntry.stopToManageFieldReferences();
return newEntry;
}
@@ -484,7 +484,7 @@ public class EntryEditActivity extends LockingHideActivity
}
// Don't start the field reference manager, we want to see the raw ref
- mEntry.endToManageFieldReferences();
+ mEntry.stopToManageFieldReferences();
entryTitleView.setText(mEntry.getTitle());
entryUserNameView.setText(mEntry.getUsername());
diff --git a/app/src/main/java/com/kunzisoft/keepass/activities/GroupActivity.java b/app/src/main/java/com/kunzisoft/keepass/activities/GroupActivity.java
index ac682ac09..f0a8a3f70 100644
--- a/app/src/main/java/com/kunzisoft/keepass/activities/GroupActivity.java
+++ b/app/src/main/java/com/kunzisoft/keepass/activities/GroupActivity.java
@@ -19,6 +19,7 @@
*/
package com.kunzisoft.keepass.activities;
+import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Dialog;
import android.app.SearchManager;
@@ -29,24 +30,31 @@ import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.TypedArray;
import android.graphics.Color;
+import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentTransaction;
import android.support.v7.widget.SearchView;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
+import android.view.View;
import android.widget.ImageView;
+import android.widget.TextView;
import com.getkeepsafe.taptargetview.TapTarget;
import com.getkeepsafe.taptargetview.TapTargetView;
import com.kunzisoft.keepass.R;
import com.kunzisoft.keepass.adapters.NodeAdapter;
+import com.kunzisoft.keepass.adapters.SearchEntryCursorAdapter;
import com.kunzisoft.keepass.app.App;
import com.kunzisoft.keepass.autofill.AutofillHelper;
import com.kunzisoft.keepass.database.Database;
@@ -57,6 +65,7 @@ import com.kunzisoft.keepass.database.PwGroupId;
import com.kunzisoft.keepass.database.PwIcon;
import com.kunzisoft.keepass.database.PwIconStandard;
import com.kunzisoft.keepass.database.PwNode;
+import com.kunzisoft.keepass.database.SortNodeEnum;
import com.kunzisoft.keepass.database.action.node.AddGroupRunnable;
import com.kunzisoft.keepass.database.action.node.AfterActionNodeOnFinish;
import com.kunzisoft.keepass.database.action.node.CopyEntryRunnable;
@@ -69,48 +78,64 @@ import com.kunzisoft.keepass.dialogs.AssignMasterKeyDialogFragment;
import com.kunzisoft.keepass.dialogs.GroupEditDialogFragment;
import com.kunzisoft.keepass.dialogs.IconPickerDialogFragment;
import com.kunzisoft.keepass.dialogs.ReadOnlyDialog;
+import com.kunzisoft.keepass.dialogs.SortDialogFragment;
import com.kunzisoft.keepass.icons.IconPackChooser;
-import com.kunzisoft.keepass.search.SearchResultsActivity;
+import com.kunzisoft.keepass.lock.LockingActivity;
+import com.kunzisoft.keepass.password.AssignPasswordHelper;
import com.kunzisoft.keepass.selection.EntrySelectionHelper;
import com.kunzisoft.keepass.settings.PreferencesUtil;
import com.kunzisoft.keepass.tasks.SaveDatabaseProgressTaskDialogFragment;
import com.kunzisoft.keepass.tasks.UIToastTask;
import com.kunzisoft.keepass.tasks.UpdateProgressTaskStatus;
+import com.kunzisoft.keepass.utils.MenuUtil;
import com.kunzisoft.keepass.view.AddNodeButtonView;
import net.cachapa.expandablelayout.ExpandableLayout;
import static com.kunzisoft.keepass.activities.ReadOnlyHelper.READ_ONLY_DEFAULT;
-public class GroupActivity extends ListNodesActivity
+public class GroupActivity extends LockingActivity
implements GroupEditDialogFragment.EditGroupListener,
IconPickerDialogFragment.IconPickerListener,
NodeAdapter.NodeMenuListener,
- ListNodesFragment.OnScrollListener {
+ ListNodesFragment.OnScrollListener,
+ AssignMasterKeyDialogFragment.AssignPasswordDialogListener,
+ NodeAdapter.NodeClickCallback,
+ SortDialogFragment.SortSelectionListener {
private static final String TAG = GroupActivity.class.getName();
- protected static final String GROUP_ID_KEY = "GROUP_ID_KEY";
+ private static final String GROUP_ID_KEY = "GROUP_ID_KEY";
+ private static final String LIST_NODES_FRAGMENT_TAG = "LIST_NODES_FRAGMENT_TAG";
+ private static final String SEARCH_FRAGMENT_TAG = "SEARCH_FRAGMENT_TAG";
+ private static final String OLD_GROUP_TO_UPDATE_KEY = "OLD_GROUP_TO_UPDATE_KEY";
+ private static final String NODE_TO_COPY_KEY = "NODE_TO_COPY_KEY";
+ private static final String NODE_TO_MOVE_KEY = "NODE_TO_MOVE_KEY";
private Toolbar toolbar;
-
+ private View searchTitleView;
private ExpandableLayout toolbarPasteExpandableLayout;
private Toolbar toolbarPaste;
-
private ImageView iconView;
private AddNodeButtonView addNodeButtonView;
+ private TextView groupNameView;
- protected boolean addGroupEnabled = false;
- protected boolean addEntryEnabled = false;
- protected boolean isRoot = false;
+ private Database database;
- private static final String OLD_GROUP_TO_UPDATE_KEY = "OLD_GROUP_TO_UPDATE_KEY";
- private static final String NODE_TO_COPY_KEY = "NODE_TO_COPY_KEY";
- private static final String NODE_TO_MOVE_KEY = "NODE_TO_MOVE_KEY";
+ private ListNodesFragment listNodesFragment;
+ private boolean currentGroupIsASearch;
+
+ private PwGroup rootGroup;
+ private PwGroup mCurrentGroup;
private PwGroup oldGroupToUpdate;
private PwNode nodeToCopy;
private PwNode nodeToMove;
+ private boolean entrySelectionMode;
+ private AutofillHelper autofillHelper;
+
+ private SearchEntryCursorAdapter searchSuggestionAdapter;
+
// After a database creation
public static void launch(Activity act) {
launch(act, READ_ONLY_DEFAULT);
@@ -176,39 +201,37 @@ public class GroupActivity extends ListNodesActivity
@Override
protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
+ super.onCreate(savedInstanceState);
- Log.i(TAG, "Started creating tree");
- if ( mCurrentGroup == null ) {
- Log.w(TAG, "Group was null");
- return;
- }
+ if ( isFinishing() ) {
+ return;
+ }
+
+ database = App.getDB();
+ // Likely the app has been killed exit the activity
+ if ( ! database.getLoaded() ) {
+ finish();
+ return;
+ }
// Construct main view
setContentView(getLayoutInflater().inflate(R.layout.list_nodes_with_add_button, null));
- attachFragmentToContentView();
-
+ // Initialize views
iconView = findViewById(R.id.icon);
addNodeButtonView = findViewById(R.id.add_node_button);
- addNodeButtonView.enableAddGroup(addGroupEnabled);
- addNodeButtonView.enableAddEntry(addEntryEnabled);
-
toolbar = findViewById(R.id.toolbar);
- toolbar.setTitle("");
- setSupportActionBar(toolbar);
+ searchTitleView = findViewById(R.id.search_title);
groupNameView = findViewById(R.id.group_name);
-
toolbarPasteExpandableLayout = findViewById(R.id.expandable_toolbar_paste_layout);
toolbarPaste = findViewById(R.id.toolbar_paste);
- toolbarPaste.inflateMenu(R.menu.node_paste_menu);
- toolbarPaste.setNavigationIcon(R.drawable.ic_arrow_left_white_24dp);
- toolbarPaste.setNavigationOnClickListener(view -> {
- toolbarPasteExpandableLayout.collapse();
- nodeToCopy = null;
- nodeToMove = null;
- });
+ invalidateOptionsMenu();
+
+ // Get arg from intent or instance state
+ readOnly = ReadOnlyHelper.retrieveReadOnlyFromInstanceStateOrIntent(savedInstanceState, getIntent());
+
+ // Retrieve elements after an orientation change
if (savedInstanceState != null) {
if (savedInstanceState.containsKey(OLD_GROUP_TO_UPDATE_KEY))
oldGroupToUpdate = savedInstanceState.getParcelable(OLD_GROUP_TO_UPDATE_KEY);
@@ -223,21 +246,124 @@ public class GroupActivity extends ListNodesActivity
}
}
- addNodeButtonView.setAddGroupClickListener(v -> {
- GroupEditDialogFragment.build()
- .show(getSupportFragmentManager(),
- GroupEditDialogFragment.TAG_CREATE_GROUP);
+ rootGroup = database.getPwDatabase().getRootGroup();
+ mCurrentGroup = retrieveCurrentGroup(getIntent(), savedInstanceState);
+ currentGroupIsASearch = Intent.ACTION_SEARCH.equals(getIntent().getAction());
+
+ Log.i(TAG, "Started creating tree");
+ if ( mCurrentGroup == null ) {
+ Log.w(TAG, "Group was null");
+ return;
+ }
+
+ toolbar.setTitle("");
+ setSupportActionBar(toolbar);
+
+ toolbarPaste.inflateMenu(R.menu.node_paste_menu);
+ toolbarPaste.setNavigationIcon(R.drawable.ic_arrow_left_white_24dp);
+ toolbarPaste.setNavigationOnClickListener(view -> {
+ toolbarPasteExpandableLayout.collapse();
+ nodeToCopy = null;
+ nodeToMove = null;
});
+
+ String fragmentTag = LIST_NODES_FRAGMENT_TAG;
+ if (currentGroupIsASearch)
+ fragmentTag = SEARCH_FRAGMENT_TAG;
+
+ // Initialize the fragment with the list
+ listNodesFragment = (ListNodesFragment) getSupportFragmentManager()
+ .findFragmentByTag(fragmentTag);
+ if (listNodesFragment == null)
+ listNodesFragment = ListNodesFragment.newInstance(mCurrentGroup, readOnly, currentGroupIsASearch);
+
+ // Attach fragment to content view
+ getSupportFragmentManager().beginTransaction().replace(
+ R.id.nodes_list_fragment_container,
+ listNodesFragment,
+ fragmentTag)
+ .commit();
+
+ // Add listeners to the add buttons
+ addNodeButtonView.setAddGroupClickListener(v -> GroupEditDialogFragment.build()
+ .show(getSupportFragmentManager(),
+ GroupEditDialogFragment.TAG_CREATE_GROUP));
addNodeButtonView.setAddEntryClickListener(v ->
EntryEditActivity.launch(GroupActivity.this, mCurrentGroup));
- Log.i(TAG, "Finished creating tree");
-
- if (isRoot) {
- showWarnings();
+ // To init autofill
+ entrySelectionMode = EntrySelectionHelper.isIntentInEntrySelectionMode(getIntent());
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ autofillHelper = new AutofillHelper();
+ autofillHelper.retrieveAssistStructure(getIntent());
}
+
+ // Search suggestion
+ searchSuggestionAdapter = new SearchEntryCursorAdapter(this, database);
+
+ Log.i(TAG, "Finished creating tree");
}
+ @Override
+ protected void onNewIntent(Intent intent) {
+ setIntent(intent);
+ if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
+ // only one instance of search in backstack
+ openSearchGroup(retrieveCurrentGroup(intent, null));
+ currentGroupIsASearch = true;
+ } else {
+ currentGroupIsASearch = false;
+ }
+ }
+
+ private void openSearchGroup(PwGroup group) {
+ // Delete the previous search fragment
+ Fragment searchFragment = getSupportFragmentManager().findFragmentByTag(SEARCH_FRAGMENT_TAG);
+ if (searchFragment != null) {
+ if ( getSupportFragmentManager()
+ .popBackStackImmediate(SEARCH_FRAGMENT_TAG, FragmentManager.POP_BACK_STACK_INCLUSIVE) )
+ getSupportFragmentManager().beginTransaction().remove(searchFragment).commit();
+ }
+
+ openGroup(group, true);
+ }
+
+ private void openChildGroup(PwGroup group) {
+ openGroup(group, false);
+ }
+
+ private void openGroup(PwGroup group, boolean isASearch) {
+ // Check Timeout
+ if (checkTimeIsAllowedOrFinish(this)) {
+ startRecordTime(this);
+
+ // Open a group in a new fragment
+ ListNodesFragment newListNodeFragment = ListNodesFragment.newInstance(group, readOnly, isASearch);
+ FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
+ // Different animation
+ String fragmentTag;
+ if (isASearch) {
+ fragmentTransaction.setCustomAnimations(R.anim.slide_in_top, R.anim.slide_out_bottom,
+ R.anim.slide_in_bottom, R.anim.slide_out_top);
+ fragmentTag = SEARCH_FRAGMENT_TAG;
+ } else {
+ fragmentTransaction.setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_left,
+ R.anim.slide_in_left, R.anim.slide_out_right);
+ fragmentTag = LIST_NODES_FRAGMENT_TAG;
+ }
+
+ fragmentTransaction.replace(R.id.nodes_list_fragment_container,
+ newListNodeFragment,
+ fragmentTag);
+ fragmentTransaction.addToBackStack(fragmentTag);
+ fragmentTransaction.commit();
+
+ listNodesFragment = newListNodeFragment;
+ mCurrentGroup = group;
+ assignGroupViewElements();
+ }
+ }
+
@Override
protected void onSaveInstanceState(Bundle outState) {
outState.putParcelable(GROUP_ID_KEY, mCurrentGroup.getId());
@@ -246,65 +372,113 @@ public class GroupActivity extends ListNodesActivity
outState.putParcelable(NODE_TO_COPY_KEY, nodeToCopy);
if (nodeToMove != null)
outState.putParcelable(NODE_TO_MOVE_KEY, nodeToMove);
+ ReadOnlyHelper.onSaveInstanceState(outState, readOnly);
super.onSaveInstanceState(outState);
}
- protected PwGroup retrieveCurrentGroup(@Nullable Bundle savedInstanceState) {
+ protected PwGroup retrieveCurrentGroup(Intent intent, @Nullable Bundle savedInstanceState) {
- PwGroupId pwGroupId = null;
- if (savedInstanceState != null
- && savedInstanceState.containsKey(GROUP_ID_KEY)) {
- pwGroupId = savedInstanceState.getParcelable(GROUP_ID_KEY);
- } else {
- if (getIntent() != null)
- pwGroupId = getIntent().getParcelableExtra(GROUP_ID_KEY);
+ // If it's a search
+ if ( Intent.ACTION_SEARCH.equals(intent.getAction()) ) {
+ return database.search(intent.getStringExtra(SearchManager.QUERY).trim());
}
+ // else a real group
+ else {
+ PwGroupId pwGroupId = null;
+ if (savedInstanceState != null
+ && savedInstanceState.containsKey(GROUP_ID_KEY)) {
+ pwGroupId = savedInstanceState.getParcelable(GROUP_ID_KEY);
+ } else {
+ if (getIntent() != null)
+ pwGroupId = intent.getParcelableExtra(GROUP_ID_KEY);
+ }
- readOnly = database.isReadOnly() || readOnly; // Force read only if the database is like that
+ readOnly = database.isReadOnly() || readOnly; // Force read only if the database is like that
- Log.w(TAG, "Creating tree view");
- PwGroup currentGroup;
- if ( pwGroupId == null ) {
- currentGroup = rootGroup;
- } else {
- currentGroup = database.getPwDatabase().getGroupByGroupId(pwGroupId);
+ Log.w(TAG, "Creating tree view");
+ PwGroup currentGroup;
+ if (pwGroupId == null) {
+ currentGroup = rootGroup;
+ } else {
+ currentGroup = database.getPwDatabase().getGroupByGroupId(pwGroupId);
+ }
+
+ return currentGroup;
}
-
- if (currentGroup != null) {
- addGroupEnabled = !readOnly;
- addEntryEnabled = !readOnly;
- isRoot = (currentGroup == rootGroup);
- if (!currentGroup.allowAddEntryIfIsRoot())
- addEntryEnabled = !isRoot && addEntryEnabled;
- }
-
- return currentGroup;
}
- @Override
- public void assignToolbarElements() {
- super.assignToolbarElements();
-
- // Assign the group icon depending of IconPack or custom icon
- if ( mCurrentGroup != null ) {
- if (IconPackChooser.getSelectedIconPack(this).tintable()) {
- // Retrieve the textColor to tint the icon
- int[] attrs = {R.attr.textColorInverse};
- TypedArray ta = getTheme().obtainStyledAttributes(attrs);
- int iconColor = ta.getColor(0, Color.WHITE);
- App.getDB().getDrawFactory().assignDatabaseIconTo(this, iconView, mCurrentGroup.getIcon(), true, iconColor);
+ public void assignGroupViewElements() {
+ // Assign title
+ if (mCurrentGroup != null) {
+ String title = mCurrentGroup.getName();
+ if (title != null && title.length() > 0) {
+ if (groupNameView != null) {
+ groupNameView.setText(title);
+ groupNameView.invalidate();
+ }
} else {
- App.getDB().getDrawFactory().assignDatabaseIconTo(this, iconView, mCurrentGroup.getIcon());
- }
-
- if (toolbar != null) {
- if ( mCurrentGroup.containsParent() )
- toolbar.setNavigationIcon(R.drawable.ic_arrow_up_white_24dp);
- else {
- toolbar.setNavigationIcon(null);
+ if (groupNameView != null) {
+ groupNameView.setText(getText(R.string.root));
+ groupNameView.invalidate();
}
}
}
+ if (currentGroupIsASearch) {
+ searchTitleView.setVisibility(View.VISIBLE);
+ } else {
+ searchTitleView.setVisibility(View.GONE);
+ }
+
+ // Assign icon
+ if (currentGroupIsASearch) {
+ if (toolbar != null) {
+ toolbar.setNavigationIcon(null);
+ }
+ iconView.setVisibility(View.GONE);
+ } else {
+ // Assign the group icon depending of IconPack or custom icon
+ iconView.setVisibility(View.VISIBLE);
+ if (mCurrentGroup != null) {
+ if (IconPackChooser.getSelectedIconPack(this).tintable()) {
+ // Retrieve the textColor to tint the icon
+ int[] attrs = {R.attr.textColorInverse};
+ TypedArray ta = getTheme().obtainStyledAttributes(attrs);
+ int iconColor = ta.getColor(0, Color.WHITE);
+ App.getDB().getDrawFactory().assignDatabaseIconTo(this, iconView, mCurrentGroup.getIcon(), true, iconColor);
+ } else {
+ App.getDB().getDrawFactory().assignDatabaseIconTo(this, iconView, mCurrentGroup.getIcon());
+ }
+
+ if (toolbar != null) {
+ if (mCurrentGroup.containsParent())
+ toolbar.setNavigationIcon(R.drawable.ic_arrow_up_white_24dp);
+ else {
+ toolbar.setNavigationIcon(null);
+ }
+ }
+ }
+ }
+
+ // Show button if allowed
+ if (addNodeButtonView != null) {
+
+ // To enable add button
+ boolean addGroupEnabled = !readOnly && !currentGroupIsASearch;
+ boolean addEntryEnabled = !readOnly && !currentGroupIsASearch;
+ if (mCurrentGroup != null) {
+ boolean isRoot = (mCurrentGroup == rootGroup);
+ if (!mCurrentGroup.allowAddEntryIfIsRoot())
+ addEntryEnabled = !isRoot && addEntryEnabled;
+ if (isRoot) {
+ showWarnings();
+ }
+ }
+ addNodeButtonView.enableAddGroup(addGroupEnabled);
+ addNodeButtonView.enableAddEntry(addEntryEnabled);
+
+ if (addNodeButtonView.isEnable())
+ addNodeButtonView.showButton();
+ }
}
@Override
@@ -313,6 +487,50 @@ public class GroupActivity extends ListNodesActivity
addNodeButtonView.hideButtonOnScrollListener(dy);
}
+ @Override
+ public void onNodeClick(PwNode node) {
+
+ // Add event when we have Autofill
+ AssistStructure assistStructure = null;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ assistStructure = autofillHelper.getAssistStructure();
+ if (assistStructure != null) {
+ switch (node.getType()) {
+ case GROUP:
+ openChildGroup((PwGroup) node);
+ break;
+ case ENTRY:
+ // Build response with the entry selected
+ autofillHelper.buildResponseWhenEntrySelected(this, (PwEntry) node);
+ finish();
+ break;
+ }
+ }
+ }
+ if ( assistStructure == null ){
+ if (entrySelectionMode) {
+ switch (node.getType()) {
+ case GROUP:
+ openChildGroup((PwGroup) node);
+ break;
+ case ENTRY:
+ EntrySelectionHelper.buildResponseWhenEntrySelected(this, (PwEntry) node);
+ finish();
+ break;
+ }
+ } else {
+ switch (node.getType()) {
+ case GROUP:
+ openChildGroup((PwGroup) node);
+ break;
+ case ENTRY:
+ EntryActivity.launch(this, (PwEntry) node, readOnly);
+ break;
+ }
+ }
+ }
+ }
+
@Override
public boolean onOpenMenuClick(PwNode node) {
onNodeClick(node);
@@ -485,9 +703,8 @@ public class GroupActivity extends ListNodesActivity
@Override
protected void onResume() {
super.onResume();
- // Show button on resume
- if (addNodeButtonView != null)
- addNodeButtonView.showButton();
+ // Refresh the elements
+ assignGroupViewElements();
}
/**
@@ -501,7 +718,7 @@ public class GroupActivity extends ListNodesActivity
if (listNodesFragment != null
&& listNodesFragment.isEmpty()) {
if (!PreferencesUtil.isEducationNewNodePerformed(this)
- && addNodeButtonView.isVisible()) {
+ && addNodeButtonView.isEnable()) {
TapTargetView.showFor(this,
TapTarget.forView(findViewById(R.id.add_button),
@@ -652,11 +869,26 @@ public class GroupActivity extends ListNodesActivity
searchView = (SearchView) searchItem.getActionView();
}
if (searchView != null) {
- // TODO Flickering when locking, will be better with content provider
- searchView.setSearchableInfo(searchManager.getSearchableInfo(new ComponentName(this, SearchResultsActivity.class)));
+ searchView.setSearchableInfo(searchManager.getSearchableInfo(new ComponentName(this, GroupActivity.class)));
searchView.setIconifiedByDefault(false); // Do not iconify the widget; expand it by default
+ searchView.setSuggestionsAdapter(searchSuggestionAdapter);
+ searchView.setOnSuggestionListener(new SearchView.OnSuggestionListener() {
+ @Override
+ public boolean onSuggestionClick(int position) {
+ onNodeClick(searchSuggestionAdapter.getEntryFromPosition(position));
+ return true;
+ }
+
+ @Override
+ public boolean onSuggestionSelect(int position) {
+ return true;
+ }
+ });
}
+ MenuUtil.contributionMenuInflater(inflater, menu);
+ inflater.inflate(R.menu.default_menu, menu);
+
super.onCreateOptionsMenu(menu);
// Launch education screen
@@ -673,7 +905,7 @@ public class GroupActivity extends ListNodesActivity
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
String query = intent.getStringExtra(SearchManager.QUERY);
// manually launch the real search activity
- final Intent searchIntent = new Intent(getApplicationContext(), SearchResultsActivity.class);
+ final Intent searchIntent = new Intent(getApplicationContext(), GroupActivity.class);
// add query to the Intent Extras
searchIntent.setAction(Intent.ACTION_SEARCH);
searchIntent.putExtra(SearchManager.QUERY, query);
@@ -706,7 +938,7 @@ public class GroupActivity extends ListNodesActivity
return true;
case R.id.menu_search:
- onSearchRequested();
+ //onSearchRequested();
return true;
case R.id.menu_lock:
@@ -716,8 +948,11 @@ public class GroupActivity extends ListNodesActivity
case R.id.menu_change_master_key:
setPassword();
return true;
+ default:
+ // Check the time lock before launching settings
+ MenuUtil.onDefaultMenuOptionsItemSelected(this, item, readOnly, true);
+ return super.onOptionsItemSelected(item);
}
- return super.onOptionsItemSelected(item);
}
private void setPassword() {
@@ -789,6 +1024,7 @@ public class GroupActivity extends ListNodesActivity
class AfterAddNode extends AfterActionNodeOnFinish {
+ @Override
public void run(PwNode oldNode, PwNode newNode) {
super.run();
@@ -807,6 +1043,7 @@ public class GroupActivity extends ListNodesActivity
class AfterUpdateNode extends AfterActionNodeOnFinish {
+ @Override
public void run(PwNode oldNode, PwNode newNode) {
super.run();
@@ -892,16 +1129,79 @@ public class GroupActivity extends ListNodesActivity
}
@Override
- protected void openGroup(PwGroup group) {
- super.openGroup(group);
- if (addNodeButtonView != null)
- addNodeButtonView.showButton();
+ public void onAssignKeyDialogPositiveClick(
+ boolean masterPasswordChecked, String masterPassword,
+ boolean keyFileChecked, Uri keyFile) {
+
+ AssignPasswordHelper assignPasswordHelper =
+ new AssignPasswordHelper(this,
+ masterPasswordChecked, masterPassword, keyFileChecked, keyFile);
+ assignPasswordHelper.assignPasswordInDatabase(null);
+ }
+
+ @Override
+ public void onAssignKeyDialogNegativeClick(
+ boolean masterPasswordChecked, String masterPassword,
+ boolean keyFileChecked, Uri keyFile) {
+
+ }
+
+ @Override
+ public void onSortSelected(SortNodeEnum sortNodeEnum, boolean ascending, boolean groupsBefore, boolean recycleBinBottom) {
+ if (listNodesFragment != null)
+ listNodesFragment.onSortSelected(sortNodeEnum, ascending, groupsBefore, recycleBinBottom);
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+
+ EntrySelectionHelper.onActivityResultSetResultAndFinish(this, requestCode, resultCode, data);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ AutofillHelper.onActivityResultSetResultAndFinish(this, requestCode, resultCode, data);
+ }
+ }
+
+ @SuppressLint("RestrictedApi")
+ @Override
+ public void startActivityForResult(Intent intent, int requestCode, Bundle options) {
+ /*
+ * ACTION_SEARCH automatically forces a new task. This occurs when you open a kdb file in
+ * another app such as Files or GoogleDrive and then Search for an entry. Here we remove the
+ * FLAG_ACTIVITY_NEW_TASK flag bit allowing search to open it's activity in the current task.
+ */
+ if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
+ int flags = intent.getFlags();
+ flags &= ~Intent.FLAG_ACTIVITY_NEW_TASK;
+ intent.setFlags(flags);
+ }
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
+ super.startActivityForResult(intent, requestCode, options);
+ }
+ }
+
+ private void removeSearchInIntent(Intent intent) {
+ if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
+ currentGroupIsASearch = false;
+ intent.setAction(Intent.ACTION_DEFAULT);
+ intent.removeExtra(SearchManager.QUERY);
+ }
}
@Override
public void onBackPressed() {
- super.onBackPressed();
- if (addNodeButtonView != null)
- addNodeButtonView.showButton();
+ if (checkTimeIsAllowedOrFinish(this)) {
+ startRecordTime(this);
+
+ super.onBackPressed();
+
+ listNodesFragment = (ListNodesFragment) getSupportFragmentManager().findFragmentByTag(LIST_NODES_FRAGMENT_TAG);
+ // to refresh fragment
+ listNodesFragment.rebuildList();
+ mCurrentGroup = listNodesFragment.getMainGroup();
+ removeSearchInIntent(getIntent());
+ assignGroupViewElements();
+ }
}
}
diff --git a/app/src/main/java/com/kunzisoft/keepass/activities/ListNodesActivity.java b/app/src/main/java/com/kunzisoft/keepass/activities/ListNodesActivity.java
deleted file mode 100644
index 80d73bcdf..000000000
--- a/app/src/main/java/com/kunzisoft/keepass/activities/ListNodesActivity.java
+++ /dev/null
@@ -1,294 +0,0 @@
-/*
- * Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
- *
- * This file is part of KeePass DX.
- *
- * KeePass DX 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.
- *
- * KeePass DX 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 KeePass DX. If not, see .
- *
- */
-package com.kunzisoft.keepass.activities;
-
-import android.annotation.SuppressLint;
-import android.app.assist.AssistStructure;
-import android.content.Intent;
-import android.net.Uri;
-import android.os.Build;
-import android.os.Bundle;
-import android.support.annotation.Nullable;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.widget.TextView;
-
-import com.kunzisoft.keepass.R;
-import com.kunzisoft.keepass.adapters.NodeAdapter;
-import com.kunzisoft.keepass.app.App;
-import com.kunzisoft.keepass.autofill.AutofillHelper;
-import com.kunzisoft.keepass.database.Database;
-import com.kunzisoft.keepass.database.PwEntry;
-import com.kunzisoft.keepass.database.PwGroup;
-import com.kunzisoft.keepass.database.PwNode;
-import com.kunzisoft.keepass.database.SortNodeEnum;
-import com.kunzisoft.keepass.dialogs.AssignMasterKeyDialogFragment;
-import com.kunzisoft.keepass.dialogs.SortDialogFragment;
-import com.kunzisoft.keepass.lock.LockingActivity;
-import com.kunzisoft.keepass.password.AssignPasswordHelper;
-import com.kunzisoft.keepass.selection.EntrySelectionHelper;
-import com.kunzisoft.keepass.utils.MenuUtil;
-
-public abstract class ListNodesActivity extends LockingActivity
- implements AssignMasterKeyDialogFragment.AssignPasswordDialogListener,
- NodeAdapter.NodeClickCallback,
- SortDialogFragment.SortSelectionListener {
-
- protected static final String LIST_NODES_FRAGMENT_TAG = "LIST_NODES_FRAGMENT_TAG";
- protected ListNodesFragment listNodesFragment;
-
- protected Database database;
- protected PwGroup rootGroup;
- protected PwGroup mCurrentGroup;
- protected TextView groupNameView;
-
- protected boolean entrySelectionMode;
- protected AutofillHelper autofillHelper;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- if ( isFinishing() ) {
- return;
- }
-
- database = App.getDB();
-
- // Likely the app has been killed exit the activity
- if ( ! database.getLoaded() ) {
- finish();
- return;
- }
-
- invalidateOptionsMenu();
-
- rootGroup = database.getPwDatabase().getRootGroup();
- mCurrentGroup = retrieveCurrentGroup(savedInstanceState);
-
- initializeListNodesFragment(mCurrentGroup);
-
- entrySelectionMode = EntrySelectionHelper.isIntentInEntrySelectionMode(getIntent());
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
- autofillHelper = new AutofillHelper();
- autofillHelper.retrieveAssistStructure(getIntent());
- }
- }
-
- protected abstract PwGroup retrieveCurrentGroup(@Nullable Bundle savedInstanceState);
-
- @Override
- protected void onResume() {
- super.onResume();
- // Refresh the title
- assignToolbarElements();
- }
-
- protected void initializeListNodesFragment(PwGroup currentGroup) {
- listNodesFragment = (ListNodesFragment) getSupportFragmentManager()
- .findFragmentByTag(LIST_NODES_FRAGMENT_TAG);
- if (listNodesFragment == null)
- listNodesFragment = ListNodesFragment.newInstance(currentGroup, readOnly);
- }
-
- /**
- * Attach the fragment's list of node.
- *
- * R.id.nodes_list_fragment_container must be the id of the container
- */
- protected void attachFragmentToContentView() {
- getSupportFragmentManager().beginTransaction().replace(
- R.id.nodes_list_fragment_container,
- listNodesFragment,
- LIST_NODES_FRAGMENT_TAG)
- .commit();
- }
-
- public void assignToolbarElements() {
- if (mCurrentGroup != null) {
- String title = mCurrentGroup.getName();
- if (title != null && title.length() > 0) {
- if (groupNameView != null) {
- groupNameView.setText(title);
- groupNameView.invalidate();
- }
- } else {
- if (groupNameView != null) {
- groupNameView.setText(getText(R.string.root));
- groupNameView.invalidate();
- }
- }
- }
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- super.onCreateOptionsMenu(menu);
-
- MenuInflater inflater = getMenuInflater();
- MenuUtil.contributionMenuInflater(inflater, menu);
- inflater.inflate(R.menu.default_menu, menu);
-
- return true;
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch ( item.getItemId() ) {
- default:
- // Check the time lock before launching settings
- MenuUtil.onDefaultMenuOptionsItemSelected(this, item, readOnly, true);
- return super.onOptionsItemSelected(item);
- }
- }
-
- @Override
- public void onNodeClick(PwNode node) {
-
- // Add event when we have Autofill
- AssistStructure assistStructure = null;
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
- assistStructure = autofillHelper.getAssistStructure();
- if (assistStructure != null) {
- switch (node.getType()) {
- case GROUP:
- openGroup((PwGroup) node);
- break;
- case ENTRY:
- // Build response with the entry selected
- autofillHelper.buildResponseWhenEntrySelected(this, (PwEntry) node);
- finish();
- break;
- }
- }
- }
- if ( assistStructure == null ){
- if (entrySelectionMode) {
- switch (node.getType()) {
- case GROUP:
- openGroup((PwGroup) node);
- break;
- case ENTRY:
- EntrySelectionHelper.buildResponseWhenEntrySelected(this, (PwEntry) node);
- finish();
- break;
- }
- } else {
- switch (node.getType()) {
- case GROUP:
- openGroup((PwGroup) node);
- break;
- case ENTRY:
- EntryActivity.launch(this, (PwEntry) node, readOnly);
- break;
- }
- }
- }
- }
-
- protected void openGroup(PwGroup group) {
- // Check Timeout
- if (checkTimeIsAllowedOrFinish(this)) {
- startRecordTime(this);
-
- ListNodesFragment newListNodeFragment = ListNodesFragment.newInstance(group, readOnly);
- getSupportFragmentManager().beginTransaction()
- .setCustomAnimations(R.anim.slide_in_right, R.anim.slide_out_left,
- R.anim.slide_in_left, R.anim.slide_out_right)
- .replace(R.id.nodes_list_fragment_container,
- newListNodeFragment,
- LIST_NODES_FRAGMENT_TAG)
- .addToBackStack(LIST_NODES_FRAGMENT_TAG)
- .commit();
- listNodesFragment = newListNodeFragment;
- mCurrentGroup = group;
- assignToolbarElements();
- }
- }
-
- @Override
- public void onAssignKeyDialogPositiveClick(
- boolean masterPasswordChecked, String masterPassword,
- boolean keyFileChecked, Uri keyFile) {
-
- AssignPasswordHelper assignPasswordHelper =
- new AssignPasswordHelper(this,
- masterPasswordChecked, masterPassword, keyFileChecked, keyFile);
- assignPasswordHelper.assignPasswordInDatabase(null);
- }
-
- @Override
- public void onAssignKeyDialogNegativeClick(
- boolean masterPasswordChecked, String masterPassword,
- boolean keyFileChecked, Uri keyFile) {
-
- }
-
- @Override
- public void onSortSelected(SortNodeEnum sortNodeEnum, boolean ascending, boolean groupsBefore, boolean recycleBinBottom) {
- if (listNodesFragment != null)
- listNodesFragment.onSortSelected(sortNodeEnum, ascending, groupsBefore, recycleBinBottom);
- }
-
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- super.onActivityResult(requestCode, resultCode, data);
-
- EntrySelectionHelper.onActivityResultSetResultAndFinish(this, requestCode, resultCode, data);
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
- AutofillHelper.onActivityResultSetResultAndFinish(this, requestCode, resultCode, data);
- }
- }
-
- @SuppressLint("RestrictedApi")
- @Override
- public void startActivityForResult(Intent intent, int requestCode, Bundle options) {
- /*
- * ACTION_SEARCH automatically forces a new task. This occurs when you open a kdb file in
- * another app such as Files or GoogleDrive and then Search for an entry. Here we remove the
- * FLAG_ACTIVITY_NEW_TASK flag bit allowing search to open it's activity in the current task.
- */
- if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
- int flags = intent.getFlags();
- flags &= ~Intent.FLAG_ACTIVITY_NEW_TASK;
- intent.setFlags(flags);
- }
-
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
- super.startActivityForResult(intent, requestCode, options);
- }
- }
-
- @Override
- public void onBackPressed() {
- if (checkTimeIsAllowedOrFinish(this)) {
- startRecordTime(this);
-
- super.onBackPressed();
-
- listNodesFragment = (ListNodesFragment) getSupportFragmentManager().findFragmentByTag(LIST_NODES_FRAGMENT_TAG);
- // to refresh fragment
- listNodesFragment.rebuildList();
- mCurrentGroup = listNodesFragment.getMainGroup();
- assignToolbarElements();
- }
- }
-}
diff --git a/app/src/main/java/com/kunzisoft/keepass/activities/ListNodesFragment.java b/app/src/main/java/com/kunzisoft/keepass/activities/ListNodesFragment.java
index 8c0517971..d4f654e2e 100644
--- a/app/src/main/java/com/kunzisoft/keepass/activities/ListNodesFragment.java
+++ b/app/src/main/java/com/kunzisoft/keepass/activities/ListNodesFragment.java
@@ -34,25 +34,30 @@ public class ListNodesFragment extends StylishFragment implements
private static final String TAG = ListNodesFragment.class.getName();
private static final String GROUP_KEY = "GROUP_KEY";
+ private static final String IS_SEARCH = "IS_SEARCH";
private NodeAdapter.NodeClickCallback nodeClickCallback;
private NodeAdapter.NodeMenuListener nodeMenuListener;
private OnScrollListener onScrollListener;
private RecyclerView listView;
- protected PwGroup mCurrentGroup;
- protected NodeAdapter mAdapter;
+ private PwGroup currentGroup;
+ private NodeAdapter mAdapter;
+
+ private View notFoundView;
+ private boolean isASearchResult;
// Preferences for sorting
private SharedPreferences prefs;
private boolean readOnly;
- public static ListNodesFragment newInstance(PwGroup group, boolean readOnly) {
+ public static ListNodesFragment newInstance(PwGroup group, boolean readOnly, boolean isASearch) {
Bundle bundle = new Bundle();
if (group != null) {
bundle.putParcelable(GROUP_KEY, group);
}
+ bundle.putBoolean(IS_SEARCH, isASearch);
ReadOnlyHelper.putReadOnlyInBundle(bundle, readOnly);
ListNodesFragment listNodesFragment = new ListNodesFragment();
listNodesFragment.setArguments(bundle);
@@ -99,11 +104,17 @@ public class ListNodesFragment extends StylishFragment implements
if (getArguments() != null) {
// Contains all the group in element
if (getArguments().containsKey(GROUP_KEY)) {
- mCurrentGroup = getArguments().getParcelable(GROUP_KEY);
+ currentGroup = getArguments().getParcelable(GROUP_KEY);
+ }
+
+ if (getArguments().containsKey(IS_SEARCH)) {
+ isASearchResult = getArguments().getBoolean(IS_SEARCH);
}
}
- mAdapter = new NodeAdapter(getContextThemed(), getActivity().getMenuInflater(), readOnly);
+ mAdapter = new NodeAdapter(getContextThemed(), getActivity().getMenuInflater());
+ mAdapter.setReadOnly(readOnly);
+ mAdapter.setIsASearchResult(isASearchResult);
mAdapter.setOnNodeClickListener(nodeClickCallback);
if (nodeMenuListener != null) {
@@ -129,6 +140,7 @@ public class ListNodesFragment extends StylishFragment implements
View rootView = inflater.cloneInContext(getContextThemed())
.inflate(R.layout.list_nodes_fragment, container, false);
listView = rootView.findViewById(R.id.nodes_list);
+ notFoundView = rootView.findViewById(R.id.not_found_container);
if (onScrollListener != null) {
listView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@@ -148,11 +160,20 @@ public class ListNodesFragment extends StylishFragment implements
super.onResume();
rebuildList();
+
+ if (isASearchResult && mAdapter.isEmpty()) {
+ // To show the " no search entry found "
+ listView.setVisibility(View.GONE);
+ notFoundView.setVisibility(View.VISIBLE);
+ } else {
+ listView.setVisibility(View.VISIBLE);
+ notFoundView.setVisibility(View.GONE);
+ }
}
public void rebuildList() {
// Add elements to the list
- mAdapter.rebuildList(mCurrentGroup);
+ mAdapter.rebuildList(currentGroup);
assignListToNodeAdapter(listView);
}
@@ -174,7 +195,7 @@ public class ListNodesFragment extends StylishFragment implements
// Tell the adapter to refresh it's list
mAdapter.notifyChangeSort(sortNodeEnum, ascending, groupsBefore);
- mAdapter.rebuildList(mCurrentGroup);
+ mAdapter.rebuildList(currentGroup);
}
@Override
@@ -232,7 +253,7 @@ public class ListNodesFragment extends StylishFragment implements
mAdapter.addNode(newNode);
if (resultCode == EntryEditActivity.UPDATE_ENTRY_RESULT_CODE) {
//mAdapter.updateLastNodeRegister(newNode);
- mAdapter.rebuildList(mCurrentGroup);
+ mAdapter.rebuildList(currentGroup);
}
} else {
Log.e(this.getClass().getName(), "New node can be retrieve in Activity Result");
@@ -259,7 +280,7 @@ public class ListNodesFragment extends StylishFragment implements
}
public PwGroup getMainGroup() {
- return mCurrentGroup;
+ return currentGroup;
}
public interface OnScrollListener {
diff --git a/app/src/main/java/com/kunzisoft/keepass/adapters/NodeAdapter.java b/app/src/main/java/com/kunzisoft/keepass/adapters/NodeAdapter.java
index 118d673f3..567c4efd9 100644
--- a/app/src/main/java/com/kunzisoft/keepass/adapters/NodeAdapter.java
+++ b/app/src/main/java/com/kunzisoft/keepass/adapters/NodeAdapter.java
@@ -62,6 +62,7 @@ public class NodeAdapter extends RecyclerView.Adapter {
private NodeMenuListener nodeMenuListener;
private boolean activateContextMenu;
private boolean readOnly;
+ private boolean isASearchResult;
private int iconGroupColor;
private int iconEntryColor;
@@ -70,13 +71,14 @@ public class NodeAdapter extends RecyclerView.Adapter {
* Create node list adapter with contextMenu or not
* @param context Context to use
*/
- public NodeAdapter(final Context context, MenuInflater menuInflater, boolean readOnly) {
+ public NodeAdapter(final Context context, MenuInflater menuInflater) {
this.inflater = LayoutInflater.from(context);
this.menuInflater = menuInflater;
this.context = context;
assignPreferences();
this.activateContextMenu = false;
- this.readOnly = readOnly;
+ this.readOnly = false;
+ this.isASearchResult = false;
this.nodeSortedList = new SortedList<>(PwNode.class, new SortedListAdapterCallback(this) {
@Override public int compare(PwNode item1, PwNode item2) {
@@ -103,6 +105,14 @@ public class NodeAdapter extends RecyclerView.Adapter {
taTextColor.recycle();
}
+ public void setReadOnly(boolean readOnly) {
+ this.readOnly = readOnly;
+ }
+
+ public void setIsASearchResult(boolean isASearchResult) {
+ this.isASearchResult = isASearchResult;
+ }
+
public void setActivateContextMenu(boolean activate) {
this.activateContextMenu = activate;
}
@@ -136,6 +146,14 @@ public class NodeAdapter extends RecyclerView.Adapter {
}
}
+ /**
+ * Determine if the adapter contains or not any element
+ * @return true if the list is empty
+ */
+ public boolean isEmpty() {
+ return nodeSortedList.size() <= 0;
+ }
+
/**
* Add a node to the list
* @param node Node to add
@@ -301,29 +319,44 @@ public class NodeAdapter extends RecyclerView.Adapter {
public void onCreateContextMenu(ContextMenu contextMenu, View view, ContextMenu.ContextMenuInfo contextMenuInfo) {
menuInflater.inflate(R.menu.node_menu, contextMenu);
+ // Opening
MenuItem menuItem = contextMenu.findItem(R.id.menu_open);
menuItem.setOnMenuItemClickListener(mOnMyActionClickListener);
+
+ // Edition
if (readOnly || node.equals(App.getDB().getPwDatabase().getRecycleBin())) {
contextMenu.removeItem(R.id.menu_edit);
- contextMenu.removeItem(R.id.menu_copy);
- contextMenu.removeItem(R.id.menu_move);
- contextMenu.removeItem(R.id.menu_delete);
} else {
- // Edition
menuItem = contextMenu.findItem(R.id.menu_edit);
menuItem.setOnMenuItemClickListener(mOnMyActionClickListener);
- // Copy (not for group)
- if (node.getType().equals(PwNode.Type.ENTRY)) {
- menuItem = contextMenu.findItem(R.id.menu_copy);
- menuItem.setOnMenuItemClickListener(mOnMyActionClickListener);
- } else {
- // TODO COPY For Group
- contextMenu.removeItem(R.id.menu_copy);
- }
- // Move
+ }
+
+ // Copy (not for group)
+ if (readOnly
+ || isASearchResult
+ || node.equals(App.getDB().getPwDatabase().getRecycleBin())
+ || node.getType().equals(PwNode.Type.GROUP)) {
+ // TODO COPY For Group
+ contextMenu.removeItem(R.id.menu_copy);
+ } else {
+ menuItem = contextMenu.findItem(R.id.menu_copy);
+ menuItem.setOnMenuItemClickListener(mOnMyActionClickListener);
+ }
+
+ // Move
+ if (readOnly
+ || isASearchResult
+ || node.equals(App.getDB().getPwDatabase().getRecycleBin())) {
+ contextMenu.removeItem(R.id.menu_move);
+ } else {
menuItem = contextMenu.findItem(R.id.menu_move);
menuItem.setOnMenuItemClickListener(mOnMyActionClickListener);
- // Deletion
+ }
+
+ // Deletion
+ if (readOnly || node.equals(App.getDB().getPwDatabase().getRecycleBin())) {
+ contextMenu.removeItem(R.id.menu_delete);
+ } else {
menuItem = contextMenu.findItem(R.id.menu_delete);
menuItem.setOnMenuItemClickListener(mOnMyActionClickListener);
}
diff --git a/app/src/main/java/com/kunzisoft/keepass/adapters/SearchEntryCursorAdapter.java b/app/src/main/java/com/kunzisoft/keepass/adapters/SearchEntryCursorAdapter.java
new file mode 100644
index 000000000..85f5d09ce
--- /dev/null
+++ b/app/src/main/java/com/kunzisoft/keepass/adapters/SearchEntryCursorAdapter.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2018 Jeremy Jamet / Kunzisoft.
+ *
+ * This file is part of KeePass DX.
+ *
+ * KeePass DX 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.
+ *
+ * KeePass DX 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 KeePass DX. If not, see .
+ *
+ */
+package com.kunzisoft.keepass.adapters;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.database.Cursor;
+import android.graphics.Color;
+import android.support.v4.widget.CursorAdapter;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.kunzisoft.keepass.R;
+import com.kunzisoft.keepass.database.Database;
+import com.kunzisoft.keepass.database.PwEntry;
+import com.kunzisoft.keepass.database.PwIcon;
+import com.kunzisoft.keepass.database.PwIconFactory;
+import com.kunzisoft.keepass.database.PwIconStandard;
+import com.kunzisoft.keepass.database.cursor.EntryCursor;
+import com.kunzisoft.keepass.icons.IconPackChooser;
+
+import java.util.UUID;
+
+public class SearchEntryCursorAdapter extends CursorAdapter {
+
+ private LayoutInflater cursorInflater;
+ private Database database;
+ private int iconColor;
+
+ public SearchEntryCursorAdapter(Context context, Database database) {
+ super(context, null, CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
+ cursorInflater = (LayoutInflater) context.getSystemService(
+ Context.LAYOUT_INFLATER_SERVICE);
+ this.database = database;
+
+ // Get the icon color
+ int[] attrTextColor = {R.attr.textColorInverse};
+ TypedArray taTextColor = context.getTheme().obtainStyledAttributes(attrTextColor);
+ this.iconColor = taTextColor.getColor(0, Color.WHITE);
+ taTextColor.recycle();
+ }
+
+ @Override
+ public View newView(Context context, Cursor cursor, ViewGroup parent) {
+
+ View view = cursorInflater.inflate(R.layout.search_entry, parent ,false);
+ ViewHolder viewHolder = new ViewHolder();
+ viewHolder.imageViewIcon = view.findViewById(R.id.entry_icon);
+ viewHolder.textViewTitle = view.findViewById(R.id.entry_text);
+ view.setTag(viewHolder);
+
+ return view;
+ }
+
+ @Override
+ public void bindView(View view, Context context, Cursor cursor) {
+
+ // Retrieve elements from cursor
+ PwIconFactory iconFactory = database.getPwDatabase().getIconFactory();
+ PwIcon icon = iconFactory.getIcon(
+ new UUID(cursor.getLong(cursor.getColumnIndex(EntryCursor.COLUMN_INDEX_ICON_CUSTOM_UUID_MOST_SIGNIFICANT_BITS)),
+ cursor.getLong(cursor.getColumnIndex(EntryCursor.COLUMN_INDEX_ICON_CUSTOM_UUID_LEAST_SIGNIFICANT_BITS))));
+ if (icon.isUnknown()) {
+ icon = iconFactory.getIcon(cursor.getInt(cursor.getColumnIndex(EntryCursor.COLUMN_INDEX_ICON_STANDARD)));
+ if (icon.isUnknown())
+ icon = iconFactory.getKeyIcon();
+ }
+ String title = cursor.getString( cursor.getColumnIndex(EntryCursor.COLUMN_INDEX_TITLE) );
+
+ ViewHolder viewHolder = (ViewHolder) view.getTag();
+
+ // Assign image
+ if (IconPackChooser.getSelectedIconPack(context).tintable()) {
+ database.getDrawFactory().assignDatabaseIconTo(context, viewHolder.imageViewIcon, icon, true, iconColor);
+ } else {
+ database.getDrawFactory().assignDatabaseIconTo(context, viewHolder.imageViewIcon, icon);
+ }
+ // Assign title
+ viewHolder.textViewTitle.setText(title);
+ }
+
+ private static class ViewHolder {
+ ImageView imageViewIcon;
+ TextView textViewTitle;
+ }
+
+ @Override
+ public Cursor runQueryOnBackgroundThread(CharSequence constraint) {
+ return database.searchEntry(constraint.toString());
+ }
+
+ public PwEntry getEntryFromPosition(int position) {
+ PwEntry pwEntry = null;
+
+ Cursor cursor = this.getCursor();
+ if (cursor.moveToFirst()
+ &&
+ cursor.move(position)) {
+
+ pwEntry = database.createEntry();
+ database.populateEntry(pwEntry, cursor);
+
+ }
+ return pwEntry;
+ }
+
+}
diff --git a/app/src/main/java/com/kunzisoft/keepass/database/Database.java b/app/src/main/java/com/kunzisoft/keepass/database/Database.java
index 1f4830c52..90cd2f868 100644
--- a/app/src/main/java/com/kunzisoft/keepass/database/Database.java
+++ b/app/src/main/java/com/kunzisoft/keepass/database/Database.java
@@ -21,19 +21,21 @@ package com.kunzisoft.keepass.database;
import android.content.Context;
import android.content.res.Resources;
+import android.database.Cursor;
import android.net.Uri;
import android.util.Log;
import com.kunzisoft.keepass.crypto.keyDerivation.KdfEngine;
import com.kunzisoft.keepass.crypto.keyDerivation.KdfFactory;
+import com.kunzisoft.keepass.database.cursor.EntryCursor;
import com.kunzisoft.keepass.database.exception.ContentFileNotFoundException;
import com.kunzisoft.keepass.database.exception.InvalidDBException;
import com.kunzisoft.keepass.database.exception.PwDbOutputException;
import com.kunzisoft.keepass.database.load.Importer;
import com.kunzisoft.keepass.database.load.ImporterFactory;
import com.kunzisoft.keepass.database.save.PwDbOutput;
+import com.kunzisoft.keepass.database.search.SearchDbHelper;
import com.kunzisoft.keepass.icons.IconDrawableFactory;
-import com.kunzisoft.keepass.search.SearchDbHelper;
import com.kunzisoft.keepass.tasks.ProgressTaskUpdater;
import com.kunzisoft.keepass.utils.UriUtil;
@@ -179,13 +181,17 @@ public class Database {
}
public PwGroup search(String str) {
+ return search(str, Integer.MAX_VALUE);
+ }
+
+ public PwGroup search(String str, int max) {
if (searchHelper == null) { return null; }
try {
switch (pm.getVersion()) {
case V3:
- return ((SearchDbHelper.SearchDbHelperV3) searchHelper).search(((PwDatabaseV3) pm), str);
+ return ((SearchDbHelper.SearchDbHelperV3) searchHelper).search(((PwDatabaseV3) pm), str, max);
case V4:
- return ((SearchDbHelper.SearchDbHelperV4) searchHelper).search(((PwDatabaseV4) pm), str);
+ return ((SearchDbHelper.SearchDbHelperV4) searchHelper).search(((PwDatabaseV4) pm), str, max);
}
} catch (Exception e) {
Log.e(TAG, "Search can't be performed with this SearchHelper", e);
@@ -193,6 +199,46 @@ public class Database {
return null;
}
+ public Cursor searchEntry(String query) {
+ final EntryCursor cursor = new EntryCursor();
+
+ // TODO real content provider
+ if (!query.isEmpty()) {
+ PwGroup searchResult = search(query, 6);
+ for (int i=0; i < searchResult.numbersOfChildEntries(); i++) {
+ PwEntry entry = searchResult.getChildEntryAt(i);
+ try {
+ switch (getPwDatabase().getVersion()) {
+ case V3:
+ EntryCursor.addEntry(cursor, (PwEntryV3) entry, i);
+ case V4:
+ EntryCursor.addEntry(cursor, (PwEntryV4) entry, i);
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "This version of PwGroup can't be populated", e);
+ }
+ }
+ }
+ return cursor;
+ }
+
+ public void populateEntry(PwEntry pwEntry, Cursor cursor) {
+ // TODO invert field reference manager
+ pwEntry.startToManageFieldReferences(getPwDatabase());
+ PwIconFactory iconFactory = getPwDatabase().getIconFactory();
+ try {
+ switch (getPwDatabase().getVersion()) {
+ case V3:
+ EntryCursor.populateEntry(cursor, (PwEntryV3) pwEntry, iconFactory);
+ case V4:
+ EntryCursor.populateEntry(cursor, (PwEntryV4) pwEntry, iconFactory);
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "This version of PwGroup can't be populated", e);
+ }
+ pwEntry.stopToManageFieldReferences();
+ }
+
public void saveData(Context ctx) throws IOException, PwDbOutputException {
saveData(ctx, mUri);
}
@@ -464,7 +510,11 @@ public class Database {
}
}
- public PwEntry createEntry(PwGroup parent) {
+ public PwEntry createEntry() {
+ return createEntry(null);
+ }
+
+ public PwEntry createEntry(@Nullable PwGroup parent) {
PwEntry newPwEntry = null;
try {
switch (getPwDatabase().getVersion()) {
diff --git a/app/src/main/java/com/kunzisoft/keepass/database/PwEntry.java b/app/src/main/java/com/kunzisoft/keepass/database/PwEntry.java
index fd25c2ec6..9df7cd154 100644
--- a/app/src/main/java/com/kunzisoft/keepass/database/PwEntry.java
+++ b/app/src/main/java/com/kunzisoft/keepass/database/PwEntry.java
@@ -76,7 +76,7 @@ public abstract class PwEntry extends PwNode {
}
public void startToManageFieldReferences(PwDatabase db) {}
- public void endToManageFieldReferences() {}
+ public void stopToManageFieldReferences() {}
public abstract String getTitle();
public abstract void setTitle(String title);
diff --git a/app/src/main/java/com/kunzisoft/keepass/database/PwEntryV4.java b/app/src/main/java/com/kunzisoft/keepass/database/PwEntryV4.java
index 3b9262c3e..6170f3c5d 100644
--- a/app/src/main/java/com/kunzisoft/keepass/database/PwEntryV4.java
+++ b/app/src/main/java/com/kunzisoft/keepass/database/PwEntryV4.java
@@ -169,7 +169,7 @@ public class PwEntryV4 extends PwEntry implements ITimeLogger {
}
@Override
- public void endToManageFieldReferences() {
+ public void stopToManageFieldReferences() {
this.mDatabase = null;
this.mDecodeRef = false;
}
@@ -205,41 +205,31 @@ public class PwEntryV4 extends PwEntry implements ITimeLogger {
@Override
public void setTitle(String title) {
- PwDatabaseV4 db = mDatabase;
- boolean protect = db.getMemoryProtection().protectTitle;
-
+ boolean protect = (mDatabase != null) && mDatabase.getMemoryProtection().protectTitle;
setProtectedString(STR_TITLE, title, protect);
}
@Override
public void setUsername(String user) {
- PwDatabaseV4 db = mDatabase;
- boolean protect = db.getMemoryProtection().protectUserName;
-
+ boolean protect = (mDatabase != null) && mDatabase.getMemoryProtection().protectUserName;
setProtectedString(STR_USERNAME, user, protect);
}
@Override
public void setPassword(String pass) {
- PwDatabaseV4 db = mDatabase;
- boolean protect = db.getMemoryProtection().protectPassword;
-
+ boolean protect = (mDatabase != null) && mDatabase.getMemoryProtection().protectPassword;
setProtectedString(STR_PASSWORD, pass, protect);
}
@Override
public void setUrl(String url) {
- PwDatabaseV4 db = mDatabase;
- boolean protect = db.getMemoryProtection().protectUrl;
-
+ boolean protect = (mDatabase != null) && mDatabase.getMemoryProtection().protectUrl;
setProtectedString(STR_URL, url, protect);
}
@Override
public void setNotes(String notes) {
- PwDatabaseV4 db = mDatabase;
- boolean protect = db.getMemoryProtection().protectNotes;
-
+ boolean protect = (mDatabase != null) && mDatabase.getMemoryProtection().protectNotes;
setProtectedString(STR_NOTES, notes, protect);
}
@@ -287,7 +277,7 @@ public class PwEntryV4 extends PwEntry implements ITimeLogger {
@Override
public PwIcon getIcon() {
- if (customIcon == null || customIcon.uuid.equals(PwDatabase.UUID_ZERO)) {
+ if (customIcon == null || customIcon.getUUID().equals(PwDatabase.UUID_ZERO)) {
return super.getIcon();
} else {
return customIcon;
diff --git a/app/src/main/java/com/kunzisoft/keepass/database/PwGroupV4.java b/app/src/main/java/com/kunzisoft/keepass/database/PwGroupV4.java
index c65d88e8d..959a741af 100644
--- a/app/src/main/java/com/kunzisoft/keepass/database/PwGroupV4.java
+++ b/app/src/main/java/com/kunzisoft/keepass/database/PwGroupV4.java
@@ -225,7 +225,7 @@ public class PwGroupV4 extends PwGroup implemen
@Override
public PwIcon getIcon() {
- if (customIcon == null || customIcon.uuid.equals(PwDatabase.UUID_ZERO)) {
+ if (customIcon == null || customIcon.getUUID().equals(PwDatabase.UUID_ZERO)) {
return super.getIcon();
} else {
return customIcon;
diff --git a/app/src/main/java/com/kunzisoft/keepass/database/PwIcon.java b/app/src/main/java/com/kunzisoft/keepass/database/PwIcon.java
index bd8f37a6b..db23e3425 100644
--- a/app/src/main/java/com/kunzisoft/keepass/database/PwIcon.java
+++ b/app/src/main/java/com/kunzisoft/keepass/database/PwIcon.java
@@ -32,6 +32,8 @@ public abstract class PwIcon implements Parcelable {
protected PwIcon(Parcel in) {}
+ public abstract boolean isUnknown();
+
@Override
public int describeContents() {
return 0;
diff --git a/app/src/main/java/com/kunzisoft/keepass/database/PwIconCustom.java b/app/src/main/java/com/kunzisoft/keepass/database/PwIconCustom.java
index 7299037d3..a1d9c132b 100644
--- a/app/src/main/java/com/kunzisoft/keepass/database/PwIconCustom.java
+++ b/app/src/main/java/com/kunzisoft/keepass/database/PwIconCustom.java
@@ -26,8 +26,8 @@ import java.util.UUID;
public class PwIconCustom extends PwIcon {
public static final PwIconCustom ZERO = new PwIconCustom(PwDatabase.UUID_ZERO, new byte[0]);
- public final UUID uuid;
- public byte[] imageData;
+ private final UUID uuid;
+ private byte[] imageData;
public PwIconCustom(UUID uuid, byte[] data) {
super();
@@ -48,6 +48,23 @@ public class PwIconCustom extends PwIcon {
}
@Override
+ public boolean isUnknown() {
+ return uuid == null || this.equals(ZERO);
+ }
+
+ public UUID getUUID() {
+ return uuid;
+ }
+
+ public byte[] getImageData() {
+ return imageData;
+ }
+
+ public void setImageData(byte[] imageData) {
+ this.imageData = imageData;
+ }
+
+ @Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeSerializable(uuid);
dest.writeByteArray(imageData);
diff --git a/app/src/main/java/com/kunzisoft/keepass/database/PwIconFactory.java b/app/src/main/java/com/kunzisoft/keepass/database/PwIconFactory.java
index 480ac531c..740341ea8 100644
--- a/app/src/main/java/com/kunzisoft/keepass/database/PwIconFactory.java
+++ b/app/src/main/java/com/kunzisoft/keepass/database/PwIconFactory.java
@@ -46,8 +46,8 @@ public class PwIconFactory {
}
public PwIconStandard getFolderIcon() {
- return getIcon(PwIconStandard.FOLDER);
- }
+ return getIcon(PwIconStandard.FOLDER);
+ }
public PwIconStandard getIcon(int iconId) {
PwIconStandard icon = (PwIconStandard) cache.get(iconId);
@@ -71,25 +71,8 @@ public class PwIconFactory {
return icon;
}
- public PwIconCustom getIcon(UUID iconUuid, byte[] data) {
- PwIconCustom icon = (PwIconCustom) customCache.get(iconUuid);
-
- if (icon == null) {
- icon = new PwIconCustom(iconUuid, data);
- customCache.put(iconUuid, icon);
- } else {
- icon.imageData = data;
- }
-
- return icon;
- }
-
- public void setIconData(UUID iconUuid, byte[] data) {
- getIcon(iconUuid, data);
- }
-
public void put(PwIconCustom icon) {
- customCache.put(icon.uuid, icon);
+ customCache.put(icon.getUUID(), icon);
}
}
diff --git a/app/src/main/java/com/kunzisoft/keepass/database/PwIconStandard.java b/app/src/main/java/com/kunzisoft/keepass/database/PwIconStandard.java
index 961eff1bb..f0c73e0f9 100644
--- a/app/src/main/java/com/kunzisoft/keepass/database/PwIconStandard.java
+++ b/app/src/main/java/com/kunzisoft/keepass/database/PwIconStandard.java
@@ -22,12 +22,17 @@ package com.kunzisoft.keepass.database;
import android.os.Parcel;
public class PwIconStandard extends PwIcon {
- public final int iconId;
+ private final int iconId;
+ public static final int UNKNOWN = -1;
public static final int KEY = 0;
public static final int TRASH = 43;
public static final int FOLDER = 48;
+ public PwIconStandard() {
+ this.iconId = KEY;
+ }
+
public PwIconStandard(int iconId) {
this.iconId = iconId;
}
@@ -42,6 +47,15 @@ public class PwIconStandard extends PwIcon {
}
@Override
+ public boolean isUnknown() {
+ return iconId == UNKNOWN;
+ }
+
+ public int getIconId() {
+ return iconId;
+ }
+
+ @Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(iconId);
}
diff --git a/app/src/main/java/com/kunzisoft/keepass/database/PwNode.java b/app/src/main/java/com/kunzisoft/keepass/database/PwNode.java
index 5080afcc1..db426bad3 100644
--- a/app/src/main/java/com/kunzisoft/keepass/database/PwNode.java
+++ b/app/src/main/java/com/kunzisoft/keepass/database/PwNode.java
@@ -33,7 +33,7 @@ import org.joda.time.LocalDate;
public abstract class PwNode implements ISmallTimeLogger, Parcelable, Cloneable {
protected Parent parent = null;
- protected PwIconStandard icon = new PwIconStandard(0);
+ protected PwIconStandard icon = new PwIconStandard();
protected PwDate creation = new PwDate();
protected PwDate lastMod = new PwDate();
protected PwDate lastAccess = new PwDate();
diff --git a/app/src/main/java/com/kunzisoft/keepass/database/cursor/EntryCursor.java b/app/src/main/java/com/kunzisoft/keepass/database/cursor/EntryCursor.java
new file mode 100644
index 000000000..cddbb0b41
--- /dev/null
+++ b/app/src/main/java/com/kunzisoft/keepass/database/cursor/EntryCursor.java
@@ -0,0 +1,81 @@
+package com.kunzisoft.keepass.database.cursor;
+
+import android.database.Cursor;
+import android.database.MatrixCursor;
+import android.provider.BaseColumns;
+import android.util.Log;
+
+import com.kunzisoft.keepass.database.PwDatabase;
+import com.kunzisoft.keepass.database.PwEntry;
+import com.kunzisoft.keepass.database.PwEntryV3;
+import com.kunzisoft.keepass.database.PwEntryV4;
+import com.kunzisoft.keepass.database.PwIconCustom;
+import com.kunzisoft.keepass.database.PwIconFactory;
+import com.kunzisoft.keepass.database.PwIconStandard;
+
+import java.util.UUID;
+
+public class EntryCursor extends MatrixCursor {
+
+ public static final String _ID = BaseColumns._ID;
+ public static final String COLUMN_INDEX_UUID_MOST_SIGNIFICANT_BITS = "UUIDMostSignificantBits";
+ public static final String COLUMN_INDEX_UUID_LEAST_SIGNIFICANT_BITS = "UUIDLeastSignificantBits";
+ public static final String COLUMN_INDEX_TITLE = "title";
+ public static final String COLUMN_INDEX_ICON_STANDARD = "iconStandard";
+ public static final String COLUMN_INDEX_ICON_CUSTOM_UUID_MOST_SIGNIFICANT_BITS = "iconCustomUUIDMostSignificantBits";
+ public static final String COLUMN_INDEX_ICON_CUSTOM_UUID_LEAST_SIGNIFICANT_BITS = "iconCustomUUIDLeastSignificantBits";
+
+ public EntryCursor() {
+ super(new String[]{ _ID,
+ COLUMN_INDEX_UUID_MOST_SIGNIFICANT_BITS,
+ COLUMN_INDEX_UUID_LEAST_SIGNIFICANT_BITS,
+ COLUMN_INDEX_TITLE,
+ COLUMN_INDEX_ICON_STANDARD,
+ COLUMN_INDEX_ICON_CUSTOM_UUID_MOST_SIGNIFICANT_BITS,
+ COLUMN_INDEX_ICON_CUSTOM_UUID_LEAST_SIGNIFICANT_BITS});
+ }
+
+ public static void addEntry(MatrixCursor cursor, PwEntryV3 entry, int id) {
+ cursor.addRow(new Object[] {id,
+ entry.getUUID().getMostSignificantBits(),
+ entry.getUUID().getLeastSignificantBits(),
+ entry.getTitle(),
+ entry.getIconStandard().getIconId(),
+ PwDatabase.UUID_ZERO.getMostSignificantBits(),
+ PwDatabase.UUID_ZERO.getLeastSignificantBits()});
+ }
+
+ public static void addEntry(MatrixCursor cursor, PwEntryV4 entry, int id) {
+ cursor.addRow(new Object[] {id,
+ entry.getUUID().getMostSignificantBits(),
+ entry.getUUID().getLeastSignificantBits(),
+ entry.getTitle(),
+ entry.getIconStandard().getIconId(),
+ entry.getCustomIcon().getUUID().getMostSignificantBits(),
+ entry.getCustomIcon().getUUID().getLeastSignificantBits()});
+ }
+
+ private static void populateEntryBaseVersion(Cursor cursor, PwEntry pwEntry, PwIconFactory iconFactory) {
+ pwEntry.setUUID(
+ new UUID(cursor.getLong(cursor.getColumnIndex(EntryCursor.COLUMN_INDEX_UUID_MOST_SIGNIFICANT_BITS)),
+ cursor.getLong(cursor.getColumnIndex(EntryCursor.COLUMN_INDEX_UUID_LEAST_SIGNIFICANT_BITS))));
+ pwEntry.setTitle(cursor.getString(cursor.getColumnIndex(EntryCursor.COLUMN_INDEX_TITLE)));
+
+ PwIconStandard iconStandard = iconFactory.getIcon(cursor.getInt(cursor.getColumnIndex(EntryCursor.COLUMN_INDEX_ICON_STANDARD)));
+ pwEntry.setIcon(iconStandard);
+ }
+
+ public static void populateEntry(Cursor cursor, PwEntryV3 pwEntry, PwIconFactory iconFactory) {
+ populateEntryBaseVersion(cursor, pwEntry, iconFactory);
+ }
+
+ public static void populateEntry(Cursor cursor, PwEntryV4 pwEntry, PwIconFactory iconFactory) {
+ populateEntryBaseVersion(cursor, pwEntry, iconFactory);
+
+ PwIconCustom iconCustom = iconFactory.getIcon(
+ new UUID(cursor.getLong(cursor.getColumnIndex(EntryCursor.COLUMN_INDEX_ICON_CUSTOM_UUID_MOST_SIGNIFICANT_BITS)),
+ cursor.getLong(cursor.getColumnIndex(EntryCursor.COLUMN_INDEX_ICON_CUSTOM_UUID_LEAST_SIGNIFICANT_BITS))));
+ pwEntry.setCustomIcon(iconCustom);
+ }
+
+}
diff --git a/app/src/main/java/com/kunzisoft/keepass/database/iterator/EntrySearchStringIterator.java b/app/src/main/java/com/kunzisoft/keepass/database/iterator/EntrySearchStringIterator.java
index 36ae095a4..da3c675ff 100644
--- a/app/src/main/java/com/kunzisoft/keepass/database/iterator/EntrySearchStringIterator.java
+++ b/app/src/main/java/com/kunzisoft/keepass/database/iterator/EntrySearchStringIterator.java
@@ -22,8 +22,8 @@ package com.kunzisoft.keepass.database.iterator;
import com.kunzisoft.keepass.database.PwEntry;
import com.kunzisoft.keepass.database.PwEntryV3;
import com.kunzisoft.keepass.database.PwEntryV4;
-import com.kunzisoft.keepass.database.SearchParameters;
-import com.kunzisoft.keepass.database.SearchParametersV4;
+import com.kunzisoft.keepass.database.search.SearchParameters;
+import com.kunzisoft.keepass.database.search.SearchParametersV4;
import java.util.Iterator;
diff --git a/app/src/main/java/com/kunzisoft/keepass/database/iterator/EntrySearchStringIteratorV3.java b/app/src/main/java/com/kunzisoft/keepass/database/iterator/EntrySearchStringIteratorV3.java
index 9a690ce20..b6d6dbc8d 100644
--- a/app/src/main/java/com/kunzisoft/keepass/database/iterator/EntrySearchStringIteratorV3.java
+++ b/app/src/main/java/com/kunzisoft/keepass/database/iterator/EntrySearchStringIteratorV3.java
@@ -20,7 +20,7 @@
package com.kunzisoft.keepass.database.iterator;
import com.kunzisoft.keepass.database.PwEntryV3;
-import com.kunzisoft.keepass.database.SearchParameters;
+import com.kunzisoft.keepass.database.search.SearchParameters;
import java.util.NoSuchElementException;
diff --git a/app/src/main/java/com/kunzisoft/keepass/database/iterator/EntrySearchStringIteratorV4.java b/app/src/main/java/com/kunzisoft/keepass/database/iterator/EntrySearchStringIteratorV4.java
index a73e69dc8..3e08817a4 100644
--- a/app/src/main/java/com/kunzisoft/keepass/database/iterator/EntrySearchStringIteratorV4.java
+++ b/app/src/main/java/com/kunzisoft/keepass/database/iterator/EntrySearchStringIteratorV4.java
@@ -20,7 +20,7 @@
package com.kunzisoft.keepass.database.iterator;
import com.kunzisoft.keepass.database.PwEntryV4;
-import com.kunzisoft.keepass.database.SearchParametersV4;
+import com.kunzisoft.keepass.database.search.SearchParametersV4;
import com.kunzisoft.keepass.database.security.ProtectedString;
import java.util.Iterator;
@@ -78,18 +78,19 @@ public class EntrySearchStringIteratorV4 extends EntrySearchStringIterator {
}
private boolean searchInField(String key) {
- if (key.equals(PwEntryV4.STR_TITLE)) {
- return sp.searchInTitles;
- } else if (key.equals(PwEntryV4.STR_USERNAME)) {
- return sp.searchInUserNames;
- } else if (key.equals(PwEntryV4.STR_PASSWORD)) {
- return sp.searchInPasswords;
- } else if (key.equals(PwEntryV4.STR_URL)) {
- return sp.searchInUrls;
- } else if (key.equals(PwEntryV4.STR_NOTES)) {
- return sp.searchInNotes;
- } else {
- return sp.searchInOther;
+ switch (key) {
+ case PwEntryV4.STR_TITLE:
+ return sp.searchInTitles;
+ case PwEntryV4.STR_USERNAME:
+ return sp.searchInUserNames;
+ case PwEntryV4.STR_PASSWORD:
+ return sp.searchInPasswords;
+ case PwEntryV4.STR_URL:
+ return sp.searchInUrls;
+ case PwEntryV4.STR_NOTES:
+ return sp.searchInNotes;
+ default:
+ return sp.searchInOther;
}
}
diff --git a/app/src/main/java/com/kunzisoft/keepass/database/save/PwDbV4Output.java b/app/src/main/java/com/kunzisoft/keepass/database/save/PwDbV4Output.java
index 194dbf4cd..214af00b6 100644
--- a/app/src/main/java/com/kunzisoft/keepass/database/save/PwDbV4Output.java
+++ b/app/src/main/java/com/kunzisoft/keepass/database/save/PwDbV4Output.java
@@ -350,10 +350,10 @@ public class PwDbV4Output extends PwDbOutput {
writeObject(PwDatabaseV4XML.ElemUuid, group.getUUID());
writeObject(PwDatabaseV4XML.ElemName, group.getName());
writeObject(PwDatabaseV4XML.ElemNotes, group.getNotes());
- writeObject(PwDatabaseV4XML.ElemIcon, group.getIconStandard().iconId);
+ writeObject(PwDatabaseV4XML.ElemIcon, group.getIconStandard().getIconId());
if (!group.getCustomIcon().equals(PwIconCustom.ZERO)) {
- writeObject(PwDatabaseV4XML.ElemCustomIconID, group.getCustomIcon().uuid);
+ writeObject(PwDatabaseV4XML.ElemCustomIconID, group.getCustomIcon().getUUID());
}
writeList(PwDatabaseV4XML.ElemTimes, group);
@@ -375,10 +375,10 @@ public class PwDbV4Output extends PwDbOutput {
xml.startTag(null, PwDatabaseV4XML.ElemEntry);
writeObject(PwDatabaseV4XML.ElemUuid, entry.getUUID());
- writeObject(PwDatabaseV4XML.ElemIcon, entry.getIconStandard().iconId);
+ writeObject(PwDatabaseV4XML.ElemIcon, entry.getIconStandard().getIconId());
if (!entry.getCustomIcon().equals(PwIconCustom.ZERO)) {
- writeObject(PwDatabaseV4XML.ElemCustomIconID, entry.getCustomIcon().uuid);
+ writeObject(PwDatabaseV4XML.ElemCustomIconID, entry.getCustomIcon().getUUID());
}
writeObject(PwDatabaseV4XML.ElemFgColor, entry.getForegroundColor());
@@ -701,8 +701,8 @@ public class PwDbV4Output extends PwDbOutput {
for (PwIconCustom icon : customIcons) {
xml.startTag(null, PwDatabaseV4XML.ElemCustomIconItem);
- writeObject(PwDatabaseV4XML.ElemCustomIconItemID, icon.uuid);
- writeObject(PwDatabaseV4XML.ElemCustomIconItemData, String.valueOf(Base64Coder.encode(icon.imageData)));
+ writeObject(PwDatabaseV4XML.ElemCustomIconItemID, icon.getUUID());
+ writeObject(PwDatabaseV4XML.ElemCustomIconItemData, String.valueOf(Base64Coder.encode(icon.getImageData())));
xml.endTag(null, PwDatabaseV4XML.ElemCustomIconItem);
}
diff --git a/app/src/main/java/com/kunzisoft/keepass/database/save/PwEntryOutputV3.java b/app/src/main/java/com/kunzisoft/keepass/database/save/PwEntryOutputV3.java
index 2a640e843..c9ba3feda 100644
--- a/app/src/main/java/com/kunzisoft/keepass/database/save/PwEntryOutputV3.java
+++ b/app/src/main/java/com/kunzisoft/keepass/database/save/PwEntryOutputV3.java
@@ -84,7 +84,7 @@ public class PwEntryOutputV3 {
// Image ID
mOS.write(IMAGEID_FIELD_TYPE);
mOS.write(LONG_FOUR);
- mOS.write(LEDataOutputStream.writeIntBuf(mPE.getIconStandard().iconId));
+ mOS.write(LEDataOutputStream.writeIntBuf(mPE.getIconStandard().getIconId()));
// Title
//byte[] title = mPE.title.getBytes("UTF-8");
diff --git a/app/src/main/java/com/kunzisoft/keepass/database/save/PwGroupOutputV3.java b/app/src/main/java/com/kunzisoft/keepass/database/save/PwGroupOutputV3.java
index 74dbff568..9af15826a 100644
--- a/app/src/main/java/com/kunzisoft/keepass/database/save/PwGroupOutputV3.java
+++ b/app/src/main/java/com/kunzisoft/keepass/database/save/PwGroupOutputV3.java
@@ -93,7 +93,7 @@ public class PwGroupOutputV3 {
// Image ID
mOS.write(IMAGEID_FIELD_TYPE);
mOS.write(IMAGEID_FIELD_SIZE);
- mOS.write(LEDataOutputStream.writeIntBuf(mPG.getIconStandard().iconId));
+ mOS.write(LEDataOutputStream.writeIntBuf(mPG.getIconStandard().getIconId()));
// Level
mOS.write(LEVEL_FIELD_TYPE);
diff --git a/app/src/main/java/com/kunzisoft/keepass/database/EntrySearchHandler.java b/app/src/main/java/com/kunzisoft/keepass/database/search/EntrySearchHandler.java
similarity index 92%
rename from app/src/main/java/com/kunzisoft/keepass/database/EntrySearchHandler.java
rename to app/src/main/java/com/kunzisoft/keepass/database/search/EntrySearchHandler.java
index 24bed9df9..99753a8e2 100644
--- a/app/src/main/java/com/kunzisoft/keepass/database/EntrySearchHandler.java
+++ b/app/src/main/java/com/kunzisoft/keepass/database/search/EntrySearchHandler.java
@@ -17,8 +17,10 @@
* along with KeePass DX. If not, see .
*
*/
-package com.kunzisoft.keepass.database;
+package com.kunzisoft.keepass.database.search;
+import com.kunzisoft.keepass.database.EntryHandler;
+import com.kunzisoft.keepass.database.PwEntry;
import com.kunzisoft.keepass.database.iterator.EntrySearchStringIterator;
import java.util.Date;
diff --git a/app/src/main/java/com/kunzisoft/keepass/database/EntrySearchHandlerAll.java b/app/src/main/java/com/kunzisoft/keepass/database/search/EntrySearchHandlerAll.java
similarity index 90%
rename from app/src/main/java/com/kunzisoft/keepass/database/EntrySearchHandlerAll.java
rename to app/src/main/java/com/kunzisoft/keepass/database/search/EntrySearchHandlerAll.java
index 87e5f175d..256bd7d53 100644
--- a/app/src/main/java/com/kunzisoft/keepass/database/EntrySearchHandlerAll.java
+++ b/app/src/main/java/com/kunzisoft/keepass/database/search/EntrySearchHandlerAll.java
@@ -17,7 +17,10 @@
* along with KeePass DX. If not, see .
*
*/
-package com.kunzisoft.keepass.database;
+package com.kunzisoft.keepass.database.search;
+
+import com.kunzisoft.keepass.database.EntryHandler;
+import com.kunzisoft.keepass.database.PwEntry;
import java.util.Date;
import java.util.List;
diff --git a/app/src/main/java/com/kunzisoft/keepass/database/EntrySearchHandlerV4.java b/app/src/main/java/com/kunzisoft/keepass/database/search/EntrySearchHandlerV4.java
similarity index 92%
rename from app/src/main/java/com/kunzisoft/keepass/database/EntrySearchHandlerV4.java
rename to app/src/main/java/com/kunzisoft/keepass/database/search/EntrySearchHandlerV4.java
index b6dd0a1ce..57deea143 100644
--- a/app/src/main/java/com/kunzisoft/keepass/database/EntrySearchHandlerV4.java
+++ b/app/src/main/java/com/kunzisoft/keepass/database/search/EntrySearchHandlerV4.java
@@ -17,8 +17,11 @@
* along with KeePass DX. If not, see .
*
*/
-package com.kunzisoft.keepass.database;
+package com.kunzisoft.keepass.database.search;
+import com.kunzisoft.keepass.database.PwEntry;
+import com.kunzisoft.keepass.database.PwEntryV4;
+import com.kunzisoft.keepass.database.PwGroup;
import com.kunzisoft.keepass.utils.StrUtil;
import com.kunzisoft.keepass.utils.UuidUtil;
diff --git a/app/src/main/java/com/kunzisoft/keepass/database/EntrySearchV4.java b/app/src/main/java/com/kunzisoft/keepass/database/search/EntrySearchV4.java
similarity index 94%
rename from app/src/main/java/com/kunzisoft/keepass/database/EntrySearchV4.java
rename to app/src/main/java/com/kunzisoft/keepass/database/search/EntrySearchV4.java
index 50520f01f..1faa70801 100644
--- a/app/src/main/java/com/kunzisoft/keepass/database/EntrySearchV4.java
+++ b/app/src/main/java/com/kunzisoft/keepass/database/search/EntrySearchV4.java
@@ -17,8 +17,11 @@
* along with KeePass DX. If not, see .
*
*/
-package com.kunzisoft.keepass.database;
+package com.kunzisoft.keepass.database.search;
+import com.kunzisoft.keepass.database.EntryHandler;
+import com.kunzisoft.keepass.database.PwEntryV4;
+import com.kunzisoft.keepass.database.PwGroupV4;
import com.kunzisoft.keepass.utils.StrUtil;
import java.util.ArrayList;
diff --git a/app/src/main/java/com/kunzisoft/keepass/search/SearchDbHelper.java b/app/src/main/java/com/kunzisoft/keepass/database/search/SearchDbHelper.java
similarity index 92%
rename from app/src/main/java/com/kunzisoft/keepass/search/SearchDbHelper.java
rename to app/src/main/java/com/kunzisoft/keepass/database/search/SearchDbHelper.java
index 5cd4b7352..91351aa69 100644
--- a/app/src/main/java/com/kunzisoft/keepass/search/SearchDbHelper.java
+++ b/app/src/main/java/com/kunzisoft/keepass/database/search/SearchDbHelper.java
@@ -17,7 +17,7 @@
* along with KeePass DX. If not, see .
*
*/
-package com.kunzisoft.keepass.search;
+package com.kunzisoft.keepass.database.search;
import android.content.Context;
import android.content.SharedPreferences;
@@ -54,31 +54,33 @@ public class SearchDbHelper());
// Search all entries
Locale loc = Locale.getDefault();
qStr = qStr.toLowerCase(loc);
boolean isOmitBackup = omitBackup();
-
+
+ // TODO Search from the current group
Queue worklist = new LinkedList<>();
if (pm.getRootGroup() != null) {
worklist.add(pm.getRootGroup());
}
-
+
while (worklist.size() != 0) {
PwGroupSearch top = worklist.remove();
if (pm.isGroupSearchable(top, isOmitBackup)) {
for (PwEntrySearch entry : top.getChildEntries()) {
processEntries(entry, group.getChildEntries(), qStr, loc);
+ if (group.numbersOfChildEntries() >= max)
+ return group;
}
for (PwGroupSearch childGroup : top.getChildGroups()) {
diff --git a/app/src/main/java/com/kunzisoft/keepass/database/SearchParameters.java b/app/src/main/java/com/kunzisoft/keepass/database/search/SearchParameters.java
similarity index 97%
rename from app/src/main/java/com/kunzisoft/keepass/database/SearchParameters.java
rename to app/src/main/java/com/kunzisoft/keepass/database/search/SearchParameters.java
index af87198bf..6b671d754 100644
--- a/app/src/main/java/com/kunzisoft/keepass/database/SearchParameters.java
+++ b/app/src/main/java/com/kunzisoft/keepass/database/search/SearchParameters.java
@@ -17,7 +17,7 @@
* along with KeePass DX. If not, see .
*
*/
-package com.kunzisoft.keepass.database;
+package com.kunzisoft.keepass.database.search;
/**
* @author bpellin
diff --git a/app/src/main/java/com/kunzisoft/keepass/database/SearchParametersV4.java b/app/src/main/java/com/kunzisoft/keepass/database/search/SearchParametersV4.java
similarity index 96%
rename from app/src/main/java/com/kunzisoft/keepass/database/SearchParametersV4.java
rename to app/src/main/java/com/kunzisoft/keepass/database/search/SearchParametersV4.java
index f02c251b7..b53324a0d 100644
--- a/app/src/main/java/com/kunzisoft/keepass/database/SearchParametersV4.java
+++ b/app/src/main/java/com/kunzisoft/keepass/database/search/SearchParametersV4.java
@@ -17,7 +17,7 @@
* along with KeePass DX. If not, see .
*
*/
-package com.kunzisoft.keepass.database;
+package com.kunzisoft.keepass.database.search;
public class SearchParametersV4 extends SearchParameters implements Cloneable {
public static SearchParametersV4 DEFAULT = new SearchParametersV4();
diff --git a/app/src/main/java/com/kunzisoft/keepass/icons/IconDrawableFactory.java b/app/src/main/java/com/kunzisoft/keepass/icons/IconDrawableFactory.java
index bc192f9c8..aacccf67f 100644
--- a/app/src/main/java/com/kunzisoft/keepass/icons/IconDrawableFactory.java
+++ b/app/src/main/java/com/kunzisoft/keepass/icons/IconDrawableFactory.java
@@ -221,7 +221,7 @@ public class IconDrawableFactory {
* @return The drawable
*/
private Drawable getIconDrawable(Context context, PwIconStandard icon, boolean isTint, int tintColor) {
- int resId = IconPackChooser.getSelectedIconPack(context).iconToResId(icon.iconId);
+ int resId = IconPackChooser.getSelectedIconPack(context).iconToResId(icon.getIconId());
return getIconDrawable(context, resId, isTint, tintColor);
}
@@ -289,14 +289,14 @@ public class IconDrawableFactory {
return blank;
}
- Drawable draw = (Drawable) customIconMap.get(icon.uuid);
+ Drawable draw = (Drawable) customIconMap.get(icon.getUUID());
if (draw == null) {
- if (icon.imageData == null) {
+ if (icon.getImageData() == null) {
return blank;
}
- Bitmap bitmap = BitmapFactory.decodeByteArray(icon.imageData, 0, icon.imageData.length);
+ Bitmap bitmap = BitmapFactory.decodeByteArray(icon.getImageData(), 0, icon.getImageData().length);
// Could not understand custom icon
if (bitmap == null) {
@@ -306,7 +306,7 @@ public class IconDrawableFactory {
bitmap = resize(bitmap);
draw = new BitmapDrawable(context.getResources(), bitmap);
- customIconMap.put(icon.uuid, draw);
+ customIconMap.put(icon.getUUID(), draw);
}
return draw;
diff --git a/app/src/main/java/com/kunzisoft/keepass/search/SearchResultsActivity.java b/app/src/main/java/com/kunzisoft/keepass/search/SearchResultsActivity.java
deleted file mode 100644
index 3deb9e93c..000000000
--- a/app/src/main/java/com/kunzisoft/keepass/search/SearchResultsActivity.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
- *
- * This file is part of KeePass DX.
- *
- * KeePass DX 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.
- *
- * KeePass DX 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 KeePass DX. If not, see .
- *
- */
-package com.kunzisoft.keepass.search;
-
-import android.app.SearchManager;
-import android.content.Intent;
-import android.os.Bundle;
-import android.support.v7.widget.Toolbar;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.View;
-
-import com.kunzisoft.keepass.R;
-import com.kunzisoft.keepass.activities.ListNodesActivity;
-import com.kunzisoft.keepass.activities.ListNodesFragment;
-import com.kunzisoft.keepass.database.PwGroup;
-import com.kunzisoft.keepass.utils.MenuUtil;
-
-import javax.annotation.Nullable;
-
-public class SearchResultsActivity extends ListNodesActivity {
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- setContentView(getLayoutInflater().inflate(R.layout.search_results, null));
-
- Toolbar toolbar = findViewById(R.id.toolbar);
- toolbar.setTitle(getString(R.string.search_label));
- setSupportActionBar(toolbar);
- assert getSupportActionBar() != null;
- getSupportActionBar().setDisplayHomeAsUpEnabled(true);
- getSupportActionBar().setDisplayShowHomeEnabled(true);
- groupNameView = findViewById(R.id.group_name);
-
- attachFragmentToContentView();
-
- View notFoundView = findViewById(R.id.not_found_container);
- View listContainer = findViewById(R.id.nodes_list_fragment_container);
-
- if ( mCurrentGroup == null || mCurrentGroup.numbersOfChildEntries() < 1 ) {
- listContainer.setVisibility(View.GONE);
- notFoundView.setVisibility(View.VISIBLE);
- } else {
- listContainer.setVisibility(View.VISIBLE);
- notFoundView.setVisibility(View.GONE);
- }
- }
-
- @Override
- protected void initializeListNodesFragment(PwGroup currentGroup) {
- listNodesFragment = (ListNodesFragment) getSupportFragmentManager()
- .findFragmentByTag(LIST_NODES_FRAGMENT_TAG);
- // Directly get group and not id
- if (listNodesFragment == null)
- listNodesFragment = ListNodesFragment.newInstance(currentGroup, readOnly);
- }
-
- @Override
- protected PwGroup retrieveCurrentGroup(@Nullable Bundle savedInstanceState) {
- // Likely the app has been killed exit the activity
- if ( ! database.getLoaded() ) {
- finish();
- }
- return database.search(getSearchStr(getIntent()).trim());
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
-
- MenuInflater inflater = getMenuInflater();
- MenuUtil.contributionMenuInflater(inflater, menu);
- inflater.inflate(R.menu.default_menu, menu);
-
- return true;
- }
-
- public boolean onOptionsItemSelected(MenuItem item) {
- switch ( item.getItemId() ) {
- case android.R.id.home:
- finish();
- }
- return super.onOptionsItemSelected(item);
- }
-
- private String getSearchStr(Intent queryIntent) {
- // get and process search query here
- final String queryAction = queryIntent.getAction();
- if ( Intent.ACTION_SEARCH.equals(queryAction) ) {
- return queryIntent.getStringExtra(SearchManager.QUERY);
- }
- return "";
- }
-
-}
diff --git a/app/src/main/java/com/kunzisoft/keepass/utils/SprEngineV4.java b/app/src/main/java/com/kunzisoft/keepass/utils/SprEngineV4.java
index 451018fb4..e80fe7f7e 100644
--- a/app/src/main/java/com/kunzisoft/keepass/utils/SprEngineV4.java
+++ b/app/src/main/java/com/kunzisoft/keepass/utils/SprEngineV4.java
@@ -19,13 +19,12 @@
*/
package com.kunzisoft.keepass.utils;
-import com.kunzisoft.keepass.database.EntrySearchV4;
import com.kunzisoft.keepass.database.PwDatabase;
import com.kunzisoft.keepass.database.PwDatabaseV4;
import com.kunzisoft.keepass.database.PwEntry;
import com.kunzisoft.keepass.database.PwEntryV4;
-import com.kunzisoft.keepass.database.PwGroupV4;
-import com.kunzisoft.keepass.database.SearchParametersV4;
+import com.kunzisoft.keepass.database.search.EntrySearchV4;
+import com.kunzisoft.keepass.database.search.SearchParametersV4;
import java.util.ArrayList;
import java.util.List;
@@ -158,7 +157,7 @@ public class SprEngineV4 {
List list = new ArrayList<>();
// TODO type parameter
- EntrySearchV4 entrySearchV4 = new EntrySearchV4((PwGroupV4) ctx.db.getRootGroup());
+ EntrySearchV4 entrySearchV4 = new EntrySearchV4(ctx.db.getRootGroup());
entrySearchV4.searchEntries(sp, list);
if (list.size() > 0) {
diff --git a/app/src/main/java/com/kunzisoft/keepass/view/AddNodeButtonView.java b/app/src/main/java/com/kunzisoft/keepass/view/AddNodeButtonView.java
index b138b8da7..7386e83a3 100644
--- a/app/src/main/java/com/kunzisoft/keepass/view/AddNodeButtonView.java
+++ b/app/src/main/java/com/kunzisoft/keepass/view/AddNodeButtonView.java
@@ -189,7 +189,7 @@ public class AddNodeButtonView extends RelativeLayout {
}
}
- public boolean isVisible() {
+ public boolean isEnable() {
return getVisibility() == VISIBLE;
}
diff --git a/app/src/main/java/com/kunzisoft/keepass/view/GroupHeaderView.java b/app/src/main/java/com/kunzisoft/keepass/view/GroupHeaderView.java
deleted file mode 100644
index c1bbb9e4b..000000000
--- a/app/src/main/java/com/kunzisoft/keepass/view/GroupHeaderView.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
- *
- * This file is part of KeePass DX.
- *
- * KeePass DX 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.
- *
- * KeePass DX 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 KeePass DX. If not, see .
- *
- */
-package com.kunzisoft.keepass.view;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.RelativeLayout;
-
-import com.kunzisoft.keepass.R;
-import com.kunzisoft.keepass.app.App;
-
-public class GroupHeaderView extends RelativeLayout {
-
- public GroupHeaderView(Context context) {
- this(context, null);
- }
-
- public GroupHeaderView(Context context, AttributeSet attrs) {
- super(context, attrs);
-
- inflate(context);
- }
-
- private void inflate(Context context) {
- LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- assert inflater != null;
- inflater.inflate(R.layout.group_header, this);
-
- if (App.getDB().isReadOnly()) {
- View readOnlyIndicator = findViewById(R.id.read_only);
- readOnlyIndicator.setVisibility(VISIBLE);
- }
-
- }
-
-}
diff --git a/app/src/main/res/anim/slide_in_bottom.xml b/app/src/main/res/anim/slide_in_bottom.xml
new file mode 100644
index 000000000..775f82127
--- /dev/null
+++ b/app/src/main/res/anim/slide_in_bottom.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/anim/slide_in_top.xml b/app/src/main/res/anim/slide_in_top.xml
new file mode 100644
index 000000000..aef2d0412
--- /dev/null
+++ b/app/src/main/res/anim/slide_in_top.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/anim/slide_out_bottom.xml b/app/src/main/res/anim/slide_out_bottom.xml
new file mode 100644
index 000000000..617c3ecbd
--- /dev/null
+++ b/app/src/main/res/anim/slide_out_bottom.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/anim/slide_out_top.xml b/app/src/main/res/anim/slide_out_top.xml
new file mode 100644
index 000000000..1dcc57787
--- /dev/null
+++ b/app/src/main/res/anim/slide_out_top.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/group_header.xml b/app/src/main/res/layout/group_header.xml
deleted file mode 100644
index d0b72b741..000000000
--- a/app/src/main/res/layout/group_header.xml
+++ /dev/null
@@ -1,52 +0,0 @@
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/list_nodes_entry.xml b/app/src/main/res/layout/list_nodes_entry.xml
index df0724957..4dc1d2c06 100644
--- a/app/src/main/res/layout/list_nodes_entry.xml
+++ b/app/src/main/res/layout/list_nodes_entry.xml
@@ -40,6 +40,7 @@
android:id="@+id/entry_text"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
+ android:lines="1"
style="@style/KeepassDXStyle.TextAppearance.Default"
android:layout_centerVertical="true"
android:layout_alignParentRight="true"
diff --git a/app/src/main/res/layout/list_nodes_fragment.xml b/app/src/main/res/layout/list_nodes_fragment.xml
index 2bdcfa380..6a1e5cd06 100644
--- a/app/src/main/res/layout/list_nodes_fragment.xml
+++ b/app/src/main/res/layout/list_nodes_fragment.xml
@@ -1,6 +1,30 @@
-
\ No newline at end of file
+ android:layout_height="match_parent">
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/list_nodes_with_add_button.xml b/app/src/main/res/layout/list_nodes_with_add_button.xml
index a942b6643..7b6cb5bdb 100644
--- a/app/src/main/res/layout/list_nodes_with_add_button.xml
+++ b/app/src/main/res/layout/list_nodes_with_add_button.xml
@@ -56,13 +56,43 @@
app:popupTheme="?attr/toolbarPopupAppearance"
android:elevation="4dp"
tools:targetApi="lollipop">
-
+ android:layout_below="@+id/toolbar"
+ android:orientation="vertical">
+
+
+
+
+
+
@@ -70,10 +100,11 @@
+ app:layout_behavior="@string/appbar_scrolling_view_behavior"
+ android:layout_below="@+id/toolbar"
+ android:background="?android:attr/windowBackground" />
+
+
+
+
+
\ No newline at end of file