mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
Compare commits
28 Commits
2.5.0.0bet
...
2.5.0.0bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4f9625a3e1 | ||
|
|
7688ebd29b | ||
|
|
3f2a7f1eb3 | ||
|
|
b3d067d0c8 | ||
|
|
a3b4ad5ac1 | ||
|
|
e3b329d27f | ||
|
|
7d10c43822 | ||
|
|
fcb0d45d39 | ||
|
|
5492db0223 | ||
|
|
2207b05f5f | ||
|
|
f15a0c2591 | ||
|
|
92fb22129c | ||
|
|
ccca9c4400 | ||
|
|
0597cb4416 | ||
|
|
0602174e50 | ||
|
|
6fddc92ce7 | ||
|
|
aa30df6454 | ||
|
|
f6c61ab407 | ||
|
|
2ab81ed77c | ||
|
|
0ade035f43 | ||
|
|
73b62035d8 | ||
|
|
28837db308 | ||
|
|
85befef260 | ||
|
|
e7bbb47422 | ||
|
|
846bc7edb1 | ||
|
|
99a9842a1f | ||
|
|
33009138c3 | ||
|
|
c74b82ebd8 |
13
CHANGELOG
13
CHANGELOG
@@ -1,3 +1,16 @@
|
||||
KeepassDX (2.5.0.0beta15)
|
||||
* Read only mode
|
||||
* Best group recovery for the navigation fragment
|
||||
* Fix copies in notifications
|
||||
* Fix orientation
|
||||
* Added translations
|
||||
|
||||
KeepassDX (2.5.0.0beta14)
|
||||
* Optimize all the memory with parcelables / fix search
|
||||
|
||||
KeepassDX (2.5.0.0beta13)
|
||||
* Fix memory issue with parcelable (crash in beta12 version)
|
||||
|
||||
KeepassDX (2.5.0.0beta12)
|
||||
* Added the Magikeyboard to fill the forms (settings still in development)
|
||||
* Added move and copy for groups and entries
|
||||
|
||||
@@ -8,8 +8,8 @@ android {
|
||||
applicationId "com.kunzisoft.keepass"
|
||||
minSdkVersion 14
|
||||
targetSdkVersion 27
|
||||
versionCode = 12
|
||||
versionName = "2.5.0.0beta12"
|
||||
versionCode = 15
|
||||
versionName = "2.5.0.0beta15"
|
||||
multiDexEnabled true
|
||||
|
||||
testApplicationId = "com.kunzisoft.keepass.tests"
|
||||
|
||||
@@ -78,15 +78,15 @@ public class EntryActivity extends LockingHideActivity {
|
||||
|
||||
protected PwEntry mEntry;
|
||||
private boolean mShowPassword;
|
||||
protected boolean readOnly = false;
|
||||
|
||||
private ClipboardHelper clipboardHelper;
|
||||
private boolean firstLaunchOfActivity;
|
||||
|
||||
public static void launch(Activity act, PwEntry pw) {
|
||||
public static void launch(Activity act, PwEntry pw, boolean readOnly) {
|
||||
if (LockingActivity.checkTimeIsAllowedOrFinish(act)) {
|
||||
Intent intent = new Intent(act, EntryActivity.class);
|
||||
intent.putExtra(KEY_ENTRY, Types.UUIDtoBytes(pw.getUUID()));
|
||||
ReadOnlyHelper.putReadOnlyInIntent(intent, readOnly);
|
||||
act.startActivityForResult(intent, EntryEditActivity.ADD_OR_UPDATE_ENTRY_REQUEST_CODE);
|
||||
}
|
||||
}
|
||||
@@ -110,7 +110,7 @@ public class EntryActivity extends LockingHideActivity {
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
readOnly = db.isReadOnly();
|
||||
readOnly = db.isReadOnly() || readOnly;
|
||||
|
||||
mShowPassword = !PreferencesUtil.isPasswordMask(this);
|
||||
|
||||
|
||||
@@ -178,7 +178,7 @@ public class EntryEditActivity extends LockingHideActivity
|
||||
|
||||
PwDatabase pm = db.getPwDatabase();
|
||||
if ( uuidBytes == null ) {
|
||||
PwGroupId parentId = (PwGroupId) intent.getSerializableExtra(KEY_PARENT);
|
||||
PwGroupId parentId = intent.getParcelableExtra(KEY_PARENT);
|
||||
PwGroup parent = pm.getGroupByGroupId(parentId);
|
||||
mEntry = db.createEntry(parent);
|
||||
mIsNew = true;
|
||||
@@ -548,7 +548,7 @@ public class EntryEditActivity extends LockingHideActivity
|
||||
if (mCallbackNewEntry != null) {
|
||||
Bundle bundle = new Bundle();
|
||||
Intent intentEntry = new Intent();
|
||||
bundle.putSerializable(ADD_OR_UPDATE_ENTRY_KEY, mCallbackNewEntry);
|
||||
bundle.putParcelable(ADD_OR_UPDATE_ENTRY_KEY, mCallbackNewEntry);
|
||||
intentEntry.putExtras(bundle);
|
||||
if (mIsNew) {
|
||||
setResult(ADD_ENTRY_RESULT_CODE, intentEntry);
|
||||
|
||||
@@ -70,8 +70,8 @@ import com.kunzisoft.keepass.dialogs.GroupEditDialogFragment;
|
||||
import com.kunzisoft.keepass.dialogs.IconPickerDialogFragment;
|
||||
import com.kunzisoft.keepass.dialogs.ReadOnlyDialog;
|
||||
import com.kunzisoft.keepass.icons.IconPackChooser;
|
||||
import com.kunzisoft.keepass.selection.EntrySelectionHelper;
|
||||
import com.kunzisoft.keepass.search.SearchResultsActivity;
|
||||
import com.kunzisoft.keepass.selection.EntrySelectionHelper;
|
||||
import com.kunzisoft.keepass.settings.PreferencesUtil;
|
||||
import com.kunzisoft.keepass.tasks.SaveDatabaseProgressTaskDialogFragment;
|
||||
import com.kunzisoft.keepass.tasks.UIToastTask;
|
||||
@@ -80,6 +80,8 @@ 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
|
||||
implements GroupEditDialogFragment.EditGroupListener,
|
||||
IconPickerDialogFragment.IconPickerListener,
|
||||
@@ -88,6 +90,8 @@ public class GroupActivity extends ListNodesActivity
|
||||
|
||||
private static final String TAG = GroupActivity.class.getName();
|
||||
|
||||
protected static final String GROUP_ID_KEY = "GROUP_ID_KEY";
|
||||
|
||||
private Toolbar toolbar;
|
||||
|
||||
private ExpandableLayout toolbarPasteExpandableLayout;
|
||||
@@ -99,7 +103,6 @@ public class GroupActivity extends ListNodesActivity
|
||||
protected boolean addGroupEnabled = false;
|
||||
protected boolean addEntryEnabled = false;
|
||||
protected boolean isRoot = false;
|
||||
protected boolean readOnly = false;
|
||||
|
||||
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";
|
||||
@@ -107,64 +110,67 @@ public class GroupActivity extends ListNodesActivity
|
||||
private PwGroup oldGroupToUpdate;
|
||||
private PwNode nodeToCopy;
|
||||
private PwNode nodeToMove;
|
||||
|
||||
public static void launch(Activity act) {
|
||||
|
||||
// After a database creation
|
||||
public static void launch(Activity act) {
|
||||
launch(act, READ_ONLY_DEFAULT);
|
||||
}
|
||||
|
||||
public static void launch(Activity act, boolean readOnly) {
|
||||
startRecordTime(act);
|
||||
launch(act, null);
|
||||
launch(act, null, readOnly);
|
||||
}
|
||||
|
||||
public static void launch(Activity act, PwGroup group) {
|
||||
if (checkTimeIsAllowedOrFinish(act)) {
|
||||
Intent intent = new Intent(act, GroupActivity.class);
|
||||
private static void buildAndLaunchIntent(Activity activity, PwGroup group, boolean readOnly,
|
||||
IntentBuildLauncher intentBuildLauncher) {
|
||||
if (checkTimeIsAllowedOrFinish(activity)) {
|
||||
Intent intent = new Intent(activity, GroupActivity.class);
|
||||
if (group != null) {
|
||||
intent.putExtra(GROUP_ID_KEY, group.getId());
|
||||
}
|
||||
act.startActivityForResult(intent, 0);
|
||||
ReadOnlyHelper.putReadOnlyInIntent(intent, readOnly);
|
||||
intentBuildLauncher.startActivityForResult(intent);
|
||||
}
|
||||
}
|
||||
|
||||
public static void launchForKeyboardResult(Activity act) {
|
||||
public static void launch(Activity activity, PwGroup group, boolean readOnly) {
|
||||
buildAndLaunchIntent(activity, group, readOnly,
|
||||
(intent) -> activity.startActivityForResult(intent, 0));
|
||||
}
|
||||
|
||||
public static void launchForKeyboardResult(Activity act, boolean readOnly) {
|
||||
startRecordTime(act);
|
||||
launchForKeyboardResult(act, null);
|
||||
launchForKeyboardResult(act, null, readOnly);
|
||||
}
|
||||
|
||||
public static void launchForKeyboardResult(Activity act, PwGroup group) {
|
||||
// TODO remove
|
||||
if (checkTimeIsAllowedOrFinish(act)) {
|
||||
Intent intent = new Intent(act, GroupActivity.class);
|
||||
if (group != null) {
|
||||
intent.putExtra(GROUP_ID_KEY, group.getId());
|
||||
}
|
||||
public static void launchForKeyboardResult(Activity activity, PwGroup group, boolean readOnly) {
|
||||
// TODO implement pre search to directly open the direct group
|
||||
buildAndLaunchIntent(activity, group, readOnly, (intent) -> {
|
||||
EntrySelectionHelper.addEntrySelectionModeExtraInIntent(intent);
|
||||
act.startActivityForResult(intent, EntrySelectionHelper.ENTRY_SELECTION_RESPONSE_REQUEST_CODE);
|
||||
}
|
||||
activity.startActivityForResult(intent, EntrySelectionHelper.ENTRY_SELECTION_RESPONSE_REQUEST_CODE);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||
public static void launchForAutofillResult(Activity act, AssistStructure assistStructure) {
|
||||
public static void launchForAutofillResult(Activity act, AssistStructure assistStructure, boolean readOnly) {
|
||||
if ( assistStructure != null ) {
|
||||
startRecordTime(act);
|
||||
launchForAutofillResult(act, null, assistStructure);
|
||||
launchForAutofillResult(act, null, assistStructure, readOnly);
|
||||
} else {
|
||||
launch(act);
|
||||
launch(act, readOnly);
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||
public static void launchForAutofillResult(Activity act, PwGroup group, AssistStructure assistStructure) {
|
||||
// TODO remove
|
||||
public static void launchForAutofillResult(Activity activity, PwGroup group, AssistStructure assistStructure, boolean readOnly) {
|
||||
// TODO implement pre search to directly open the direct group
|
||||
if ( assistStructure != null ) {
|
||||
if (checkTimeIsAllowedOrFinish(act)) {
|
||||
Intent intent = new Intent(act, GroupActivity.class);
|
||||
if (group != null) {
|
||||
intent.putExtra(GROUP_ID_KEY, group.getId());
|
||||
}
|
||||
buildAndLaunchIntent(activity, group, readOnly, (intent) -> {
|
||||
AutofillHelper.addAssistStructureExtraInIntent(intent, assistStructure);
|
||||
act.startActivityForResult(intent, AutofillHelper.AUTOFILL_RESPONSE_REQUEST_CODE);
|
||||
}
|
||||
activity.startActivityForResult(intent, AutofillHelper.AUTOFILL_RESPONSE_REQUEST_CODE);
|
||||
});
|
||||
} else {
|
||||
launch(act, group);
|
||||
launch(activity, group, readOnly);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,14 +211,14 @@ public class GroupActivity extends ListNodesActivity
|
||||
|
||||
if (savedInstanceState != null) {
|
||||
if (savedInstanceState.containsKey(OLD_GROUP_TO_UPDATE_KEY))
|
||||
oldGroupToUpdate = (PwGroup) savedInstanceState.getSerializable(OLD_GROUP_TO_UPDATE_KEY);
|
||||
oldGroupToUpdate = savedInstanceState.getParcelable(OLD_GROUP_TO_UPDATE_KEY);
|
||||
|
||||
if (savedInstanceState.containsKey(NODE_TO_COPY_KEY)) {
|
||||
nodeToCopy = (PwNode) savedInstanceState.getSerializable(NODE_TO_COPY_KEY);
|
||||
nodeToCopy = savedInstanceState.getParcelable(NODE_TO_COPY_KEY);
|
||||
toolbarPaste.setOnMenuItemClickListener(new OnCopyMenuItemClickListener());
|
||||
}
|
||||
else if (savedInstanceState.containsKey(NODE_TO_MOVE_KEY)) {
|
||||
nodeToMove = (PwNode) savedInstanceState.getSerializable(NODE_TO_MOVE_KEY);
|
||||
nodeToMove = savedInstanceState.getParcelable(NODE_TO_MOVE_KEY);
|
||||
toolbarPaste.setOnMenuItemClickListener(new OnMoveMenuItemClickListener());
|
||||
}
|
||||
}
|
||||
@@ -234,42 +240,40 @@ public class GroupActivity extends ListNodesActivity
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle outState) {
|
||||
outState.putSerializable(GROUP_ID_KEY, mCurrentGroup.getId());
|
||||
outState.putSerializable(OLD_GROUP_TO_UPDATE_KEY, oldGroupToUpdate);
|
||||
outState.putParcelable(GROUP_ID_KEY, mCurrentGroup.getId());
|
||||
outState.putParcelable(OLD_GROUP_TO_UPDATE_KEY, oldGroupToUpdate);
|
||||
if (nodeToCopy != null)
|
||||
outState.putSerializable(NODE_TO_COPY_KEY, nodeToCopy);
|
||||
outState.putParcelable(NODE_TO_COPY_KEY, nodeToCopy);
|
||||
if (nodeToMove != null)
|
||||
outState.putSerializable(NODE_TO_MOVE_KEY, nodeToMove);
|
||||
outState.putParcelable(NODE_TO_MOVE_KEY, nodeToMove);
|
||||
super.onSaveInstanceState(outState);
|
||||
}
|
||||
|
||||
protected PwGroup retrieveCurrentGroup(@Nullable Bundle savedInstanceState) {
|
||||
|
||||
PwGroupId pwGroupId = null; // TODO Parcelable
|
||||
PwGroupId pwGroupId = null;
|
||||
if (savedInstanceState != null
|
||||
&& savedInstanceState.containsKey(GROUP_ID_KEY)) {
|
||||
pwGroupId = (PwGroupId) savedInstanceState.getSerializable(GROUP_ID_KEY);
|
||||
pwGroupId = savedInstanceState.getParcelable(GROUP_ID_KEY);
|
||||
} else {
|
||||
if (getIntent() != null)
|
||||
pwGroupId = (PwGroupId) getIntent().getSerializableExtra(GROUP_ID_KEY);
|
||||
pwGroupId = getIntent().getParcelableExtra(GROUP_ID_KEY);
|
||||
}
|
||||
|
||||
Database db = App.getDB();
|
||||
readOnly = db.isReadOnly();
|
||||
PwGroup root = db.getPwDatabase().getRootGroup();
|
||||
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 = root;
|
||||
currentGroup = rootGroup;
|
||||
} else {
|
||||
currentGroup = db.getPwDatabase().getGroupByGroupId(pwGroupId);
|
||||
currentGroup = database.getPwDatabase().getGroupByGroupId(pwGroupId);
|
||||
}
|
||||
|
||||
if (currentGroup != null) {
|
||||
addGroupEnabled = !readOnly;
|
||||
addEntryEnabled = !readOnly; // TODO consultation mode
|
||||
isRoot = (currentGroup == root);
|
||||
addEntryEnabled = !readOnly;
|
||||
isRoot = (currentGroup == rootGroup);
|
||||
if (!currentGroup.allowAddEntryIfIsRoot())
|
||||
addEntryEnabled = !isRoot && addEntryEnabled;
|
||||
}
|
||||
@@ -496,7 +500,8 @@ public class GroupActivity extends ListNodesActivity
|
||||
// If no node, show education to add new one
|
||||
if (listNodesFragment != null
|
||||
&& listNodesFragment.isEmpty()) {
|
||||
if (!PreferencesUtil.isEducationNewNodePerformed(this)) {
|
||||
if (!PreferencesUtil.isEducationNewNodePerformed(this)
|
||||
&& addNodeButtonView.isVisible()) {
|
||||
|
||||
TapTargetView.showFor(this,
|
||||
TapTarget.forView(findViewById(R.id.add_button),
|
||||
@@ -633,7 +638,8 @@ public class GroupActivity extends ListNodesActivity
|
||||
|
||||
MenuInflater inflater = getMenuInflater();
|
||||
inflater.inflate(R.menu.search, menu);
|
||||
inflater.inflate(R.menu.database_master_key, menu);
|
||||
if (!readOnly)
|
||||
inflater.inflate(R.menu.database_master_key, menu);
|
||||
inflater.inflate(R.menu.database_lock, menu);
|
||||
|
||||
// Get the SearchView and set the searchable configuration
|
||||
@@ -671,12 +677,19 @@ public class GroupActivity extends ListNodesActivity
|
||||
// add query to the Intent Extras
|
||||
searchIntent.setAction(Intent.ACTION_SEARCH);
|
||||
searchIntent.putExtra(SearchManager.QUERY, query);
|
||||
|
||||
if ( Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
|
||||
&& autofillHelper.getAssistStructure() != null ) {
|
||||
AutofillHelper.addAssistStructureExtraInIntent(searchIntent, autofillHelper.getAssistStructure());
|
||||
startActivityForResult(searchIntent, AutofillHelper.AUTOFILL_RESPONSE_REQUEST_CODE);
|
||||
customSearchQueryExecuted = true;
|
||||
}
|
||||
// To get the keyboard response, verify if the current intent contains the EntrySelection key
|
||||
else if (EntrySelectionHelper.isIntentInEntrySelectionMode(getIntent())){
|
||||
EntrySelectionHelper.addEntrySelectionModeExtraInIntent(searchIntent);
|
||||
startActivityForResult(searchIntent, EntrySelectionHelper.ENTRY_SELECTION_RESPONSE_REQUEST_CODE);
|
||||
customSearchQueryExecuted = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!customSearchQueryExecuted) {
|
||||
@@ -881,12 +894,14 @@ public class GroupActivity extends ListNodesActivity
|
||||
@Override
|
||||
protected void openGroup(PwGroup group) {
|
||||
super.openGroup(group);
|
||||
addNodeButtonView.showButton();
|
||||
if (addNodeButtonView != null)
|
||||
addNodeButtonView.showButton();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
super.onBackPressed();
|
||||
addNodeButtonView.showButton();
|
||||
if (addNodeButtonView != null)
|
||||
addNodeButtonView.showButton();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.kunzisoft.keepass.activities;
|
||||
|
||||
import android.content.Intent;
|
||||
|
||||
public interface IntentBuildLauncher {
|
||||
void startActivityForResult(Intent intent);
|
||||
}
|
||||
@@ -35,15 +35,16 @@ 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.selection.EntrySelectionHelper;
|
||||
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
|
||||
@@ -51,11 +52,11 @@ public abstract class ListNodesActivity extends LockingActivity
|
||||
NodeAdapter.NodeClickCallback,
|
||||
SortDialogFragment.SortSelectionListener {
|
||||
|
||||
protected static final String GROUP_ID_KEY = "GROUP_ID_KEY";
|
||||
|
||||
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;
|
||||
|
||||
@@ -69,15 +70,18 @@ public abstract class ListNodesActivity extends LockingActivity
|
||||
if ( isFinishing() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
database = App.getDB();
|
||||
|
||||
// Likely the app has been killed exit the activity
|
||||
if ( ! App.getDB().getLoaded() ) {
|
||||
if ( ! database.getLoaded() ) {
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
invalidateOptionsMenu();
|
||||
|
||||
rootGroup = database.getPwDatabase().getRootGroup();
|
||||
mCurrentGroup = retrieveCurrentGroup(savedInstanceState);
|
||||
|
||||
initializeListNodesFragment(mCurrentGroup);
|
||||
@@ -102,7 +106,7 @@ public abstract class ListNodesActivity extends LockingActivity
|
||||
listNodesFragment = (ListNodesFragment) getSupportFragmentManager()
|
||||
.findFragmentByTag(LIST_NODES_FRAGMENT_TAG);
|
||||
if (listNodesFragment == null)
|
||||
listNodesFragment = ListNodesFragment.newInstance(currentGroup);
|
||||
listNodesFragment = ListNodesFragment.newInstance(currentGroup, readOnly);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -151,7 +155,7 @@ public abstract class ListNodesActivity extends LockingActivity
|
||||
switch ( item.getItemId() ) {
|
||||
default:
|
||||
// Check the time lock before launching settings
|
||||
MenuUtil.onDefaultMenuOptionsItemSelected(this, item, true);
|
||||
MenuUtil.onDefaultMenuOptionsItemSelected(this, item, readOnly, true);
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
@@ -193,7 +197,7 @@ public abstract class ListNodesActivity extends LockingActivity
|
||||
openGroup((PwGroup) node);
|
||||
break;
|
||||
case ENTRY:
|
||||
EntryActivity.launch(this, (PwEntry) node);
|
||||
EntryActivity.launch(this, (PwEntry) node, readOnly);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -205,7 +209,7 @@ public abstract class ListNodesActivity extends LockingActivity
|
||||
if (checkTimeIsAllowedOrFinish(this)) {
|
||||
startRecordTime(this);
|
||||
|
||||
ListNodesFragment newListNodeFragment = ListNodesFragment.newInstance(group.getId());
|
||||
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)
|
||||
|
||||
@@ -20,10 +20,8 @@ import android.view.ViewGroup;
|
||||
import com.kunzisoft.keepass.R;
|
||||
import com.kunzisoft.keepass.adapters.NodeAdapter;
|
||||
import com.kunzisoft.keepass.app.App;
|
||||
import com.kunzisoft.keepass.database.Database;
|
||||
import com.kunzisoft.keepass.database.PwDatabase;
|
||||
import com.kunzisoft.keepass.database.PwGroup;
|
||||
import com.kunzisoft.keepass.database.PwGroupId;
|
||||
import com.kunzisoft.keepass.database.PwNode;
|
||||
import com.kunzisoft.keepass.database.SortNodeEnum;
|
||||
import com.kunzisoft.keepass.dialogs.SortDialogFragment;
|
||||
@@ -36,7 +34,6 @@ 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 GROUP_ID_KEY = "GROUP_ID_KEY";
|
||||
|
||||
private NodeAdapter.NodeClickCallback nodeClickCallback;
|
||||
private NodeAdapter.NodeMenuListener nodeMenuListener;
|
||||
@@ -49,21 +46,14 @@ public class ListNodesFragment extends StylishFragment implements
|
||||
// Preferences for sorting
|
||||
private SharedPreferences prefs;
|
||||
|
||||
public static ListNodesFragment newInstance(PwGroup group) {
|
||||
private boolean readOnly;
|
||||
|
||||
public static ListNodesFragment newInstance(PwGroup group, boolean readOnly) {
|
||||
Bundle bundle = new Bundle();
|
||||
if (group != null) {
|
||||
bundle.putSerializable(GROUP_KEY, group);
|
||||
}
|
||||
ListNodesFragment listNodesFragment = new ListNodesFragment();
|
||||
listNodesFragment.setArguments(bundle);
|
||||
return listNodesFragment;
|
||||
}
|
||||
|
||||
public static ListNodesFragment newInstance(PwGroupId groupId) {
|
||||
Bundle bundle=new Bundle();
|
||||
if (groupId != null) {
|
||||
bundle.putSerializable(GROUP_ID_KEY, groupId);
|
||||
bundle.putParcelable(GROUP_KEY, group);
|
||||
}
|
||||
ReadOnlyHelper.putReadOnlyInBundle(bundle, readOnly);
|
||||
ListNodesFragment listNodesFragment = new ListNodesFragment();
|
||||
listNodesFragment.setArguments(bundle);
|
||||
return listNodesFragment;
|
||||
@@ -101,46 +91,33 @@ public class ListNodesFragment extends StylishFragment implements
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setHasOptionsMenu(true);
|
||||
if ( getActivity() != null ) {
|
||||
setHasOptionsMenu(true);
|
||||
|
||||
mCurrentGroup = initCurrentGroup();
|
||||
if (getActivity() != null) {
|
||||
mAdapter = new NodeAdapter(getContextThemed(), getActivity().getMenuInflater());
|
||||
readOnly = ReadOnlyHelper.retrieveReadOnlyFromInstanceStateOrArguments(savedInstanceState, getArguments());
|
||||
|
||||
if (getArguments() != null) {
|
||||
// Contains all the group in element
|
||||
if (getArguments().containsKey(GROUP_KEY)) {
|
||||
mCurrentGroup = getArguments().getParcelable(GROUP_KEY);
|
||||
}
|
||||
}
|
||||
|
||||
mAdapter = new NodeAdapter(getContextThemed(), getActivity().getMenuInflater(), readOnly);
|
||||
mAdapter.setOnNodeClickListener(nodeClickCallback);
|
||||
|
||||
if (nodeMenuListener != null) {
|
||||
mAdapter.setActivateContextMenu(true);
|
||||
mAdapter.setNodeMenuListener(nodeMenuListener);
|
||||
}
|
||||
prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||
}
|
||||
|
||||
prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||
}
|
||||
|
||||
protected PwGroup initCurrentGroup() { // TODO Change by parcelable
|
||||
|
||||
Database db = App.getDB();
|
||||
PwGroup root = db.getPwDatabase().getRootGroup();
|
||||
|
||||
PwGroup currentGroup = null;
|
||||
if (getArguments() != null) {
|
||||
// Contains all the group in element
|
||||
if (getArguments().containsKey(GROUP_KEY)) {
|
||||
currentGroup = (PwGroup) getArguments().getSerializable(GROUP_KEY);
|
||||
}
|
||||
// Contains only the group id, so the group must be retrieve
|
||||
if (getArguments().containsKey(GROUP_ID_KEY)) {
|
||||
PwGroupId pwGroupId = (PwGroupId) getArguments().getSerializable(GROUP_ID_KEY);
|
||||
if ( pwGroupId != null )
|
||||
currentGroup = db.getPwDatabase().getGroupByGroupId(pwGroupId);
|
||||
}
|
||||
}
|
||||
|
||||
if ( currentGroup == null ) {
|
||||
currentGroup = root;
|
||||
}
|
||||
|
||||
return currentGroup;
|
||||
@Override
|
||||
public void onSaveInstanceState(@NonNull Bundle outState) {
|
||||
ReadOnlyHelper.onSaveInstanceState(outState, readOnly);
|
||||
super.onSaveInstanceState(outState);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -249,7 +226,7 @@ public class ListNodesFragment extends StylishFragment implements
|
||||
case EntryEditActivity.ADD_OR_UPDATE_ENTRY_REQUEST_CODE:
|
||||
if (resultCode == EntryEditActivity.ADD_ENTRY_RESULT_CODE ||
|
||||
resultCode == EntryEditActivity.UPDATE_ENTRY_RESULT_CODE) {
|
||||
PwNode newNode = (PwNode) data.getSerializableExtra(EntryEditActivity.ADD_OR_UPDATE_ENTRY_KEY);
|
||||
PwNode newNode = data.getParcelableExtra(EntryEditActivity.ADD_OR_UPDATE_ENTRY_KEY);
|
||||
if (newNode != null) {
|
||||
if (resultCode == EntryEditActivity.ADD_ENTRY_RESULT_CODE)
|
||||
mAdapter.addNode(newNode);
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.kunzisoft.keepass.activities;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.kunzisoft.keepass.settings.PreferencesUtil;
|
||||
|
||||
public class ReadOnlyHelper {
|
||||
|
||||
public static final String READ_ONLY_KEY = "READ_ONLY_KEY";
|
||||
|
||||
public static final boolean READ_ONLY_DEFAULT = false;
|
||||
|
||||
public static boolean retrieveReadOnlyFromInstanceStateOrPreference(Context context, Bundle savedInstanceState) {
|
||||
boolean readOnly;
|
||||
if (savedInstanceState != null
|
||||
&& savedInstanceState.containsKey(READ_ONLY_KEY)) {
|
||||
readOnly = savedInstanceState.getBoolean(READ_ONLY_KEY);
|
||||
} else {
|
||||
readOnly = PreferencesUtil.enableReadOnlyDatabase(context);
|
||||
}
|
||||
return readOnly;
|
||||
}
|
||||
|
||||
public static boolean retrieveReadOnlyFromInstanceStateOrArguments(Bundle savedInstanceState, Bundle arguments) {
|
||||
boolean readOnly = READ_ONLY_DEFAULT;
|
||||
if (savedInstanceState != null
|
||||
&& savedInstanceState.containsKey(READ_ONLY_KEY)) {
|
||||
readOnly = savedInstanceState.getBoolean(READ_ONLY_KEY);
|
||||
} else if (arguments != null
|
||||
&& arguments.containsKey(READ_ONLY_KEY)) {
|
||||
readOnly = arguments.getBoolean(READ_ONLY_KEY);
|
||||
}
|
||||
return readOnly;
|
||||
}
|
||||
|
||||
public static boolean retrieveReadOnlyFromInstanceStateOrIntent(Bundle savedInstanceState, Intent intent) {
|
||||
boolean readOnly = READ_ONLY_DEFAULT;
|
||||
if (savedInstanceState != null
|
||||
&& savedInstanceState.containsKey(READ_ONLY_KEY)) {
|
||||
readOnly = savedInstanceState.getBoolean(READ_ONLY_KEY);
|
||||
} else {
|
||||
if (intent != null)
|
||||
readOnly = intent.getBooleanExtra(READ_ONLY_KEY, READ_ONLY_DEFAULT);
|
||||
}
|
||||
return readOnly;
|
||||
}
|
||||
|
||||
public static void putReadOnlyInIntent(Intent intent, boolean readOnly) {
|
||||
intent.putExtra(READ_ONLY_KEY, readOnly);
|
||||
}
|
||||
|
||||
public static void putReadOnlyInBundle(Bundle bundle, boolean readOnly) {
|
||||
bundle.putBoolean(READ_ONLY_KEY, readOnly);
|
||||
}
|
||||
|
||||
public static void onSaveInstanceState(Bundle outState, boolean readOnly) {
|
||||
outState.putBoolean(READ_ONLY_KEY, readOnly);
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,7 @@ import android.support.annotation.NonNull;
|
||||
import android.support.v7.util.SortedList;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.support.v7.widget.util.SortedListAdapterCallback;
|
||||
import android.util.Log;
|
||||
import android.util.TypedValue;
|
||||
import android.view.ContextMenu;
|
||||
import android.view.LayoutInflater;
|
||||
@@ -33,6 +34,7 @@ import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.kunzisoft.keepass.R;
|
||||
import com.kunzisoft.keepass.app.App;
|
||||
@@ -43,6 +45,7 @@ import com.kunzisoft.keepass.icons.IconPackChooser;
|
||||
import com.kunzisoft.keepass.settings.PreferencesUtil;
|
||||
|
||||
public class NodeAdapter extends RecyclerView.Adapter<BasicViewHolder> {
|
||||
private static final String TAG = NodeAdapter.class.getName();
|
||||
|
||||
private SortedList<PwNode> nodeSortedList;
|
||||
|
||||
@@ -58,6 +61,7 @@ public class NodeAdapter extends RecyclerView.Adapter<BasicViewHolder> {
|
||||
private NodeClickCallback nodeClickCallback;
|
||||
private NodeMenuListener nodeMenuListener;
|
||||
private boolean activateContextMenu;
|
||||
private boolean readOnly;
|
||||
|
||||
private int iconGroupColor;
|
||||
private int iconEntryColor;
|
||||
@@ -66,12 +70,13 @@ public class NodeAdapter extends RecyclerView.Adapter<BasicViewHolder> {
|
||||
* Create node list adapter with contextMenu or not
|
||||
* @param context Context to use
|
||||
*/
|
||||
public NodeAdapter(final Context context, MenuInflater menuInflater) {
|
||||
public NodeAdapter(final Context context, MenuInflater menuInflater, boolean readOnly) {
|
||||
this.inflater = LayoutInflater.from(context);
|
||||
this.menuInflater = menuInflater;
|
||||
this.context = context;
|
||||
assignPreferences();
|
||||
this.activateContextMenu = false;
|
||||
this.readOnly = readOnly;
|
||||
|
||||
this.nodeSortedList = new SortedList<>(PwNode.class, new SortedListAdapterCallback<PwNode>(this) {
|
||||
@Override public int compare(PwNode item1, PwNode item2) {
|
||||
@@ -122,8 +127,12 @@ public class NodeAdapter extends RecyclerView.Adapter<BasicViewHolder> {
|
||||
public void rebuildList(PwGroup group) {
|
||||
this.nodeSortedList.clear();
|
||||
assignPreferences();
|
||||
if (group != null) {
|
||||
// TODO verify sort
|
||||
try {
|
||||
this.nodeSortedList.addAll(group.getDirectChildren());
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Can't add node elements to the list", e);
|
||||
Toast.makeText(context, "Can't add node elements to the list : " + e.getMessage(), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -210,7 +219,7 @@ public class NodeAdapter extends RecyclerView.Adapter<BasicViewHolder> {
|
||||
// Context menu
|
||||
if (activateContextMenu) {
|
||||
holder.container.setOnCreateContextMenuListener(
|
||||
new ContextMenuBuilder(subNode, nodeMenuListener));
|
||||
new ContextMenuBuilder(subNode, nodeMenuListener, readOnly));
|
||||
}
|
||||
// Assign image and text size
|
||||
// Relative size of the icon
|
||||
@@ -280,24 +289,26 @@ public class NodeAdapter extends RecyclerView.Adapter<BasicViewHolder> {
|
||||
|
||||
private PwNode node;
|
||||
private NodeMenuListener menuListener;
|
||||
private boolean readOnly;
|
||||
|
||||
ContextMenuBuilder(PwNode node, NodeMenuListener menuListener) {
|
||||
ContextMenuBuilder(PwNode node, NodeMenuListener menuListener, boolean readOnly) {
|
||||
this.menuListener = menuListener;
|
||||
this.node = node;
|
||||
this.readOnly = readOnly;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateContextMenu(ContextMenu contextMenu, View view, ContextMenu.ContextMenuInfo contextMenuInfo) {
|
||||
menuInflater.inflate(R.menu.node_menu, contextMenu);
|
||||
|
||||
// TODO COPY For Group
|
||||
if (node.getType().equals(PwNode.Type.GROUP)) {
|
||||
contextMenu.removeItem(R.id.menu_copy);
|
||||
}
|
||||
|
||||
MenuItem menuItem = contextMenu.findItem(R.id.menu_open);
|
||||
menuItem.setOnMenuItemClickListener(mOnMyActionClickListener);
|
||||
if (!App.getDB().isReadOnly() && !node.equals(App.getDB().getPwDatabase().getRecycleBin())) {
|
||||
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);
|
||||
@@ -305,6 +316,9 @@ public class NodeAdapter extends RecyclerView.Adapter<BasicViewHolder> {
|
||||
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
|
||||
menuItem = contextMenu.findItem(R.id.menu_move);
|
||||
|
||||
@@ -19,20 +19,57 @@
|
||||
*/
|
||||
package com.kunzisoft.keepass.database;
|
||||
|
||||
import java.io.Serializable;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import com.kunzisoft.keepass.utils.MemUtil;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class AutoType implements Cloneable, Serializable {
|
||||
public class AutoType implements Cloneable, Parcelable {
|
||||
private static final long OBF_OPT_NONE = 0;
|
||||
|
||||
public boolean enabled = true;
|
||||
public long obfuscationOptions = OBF_OPT_NONE;
|
||||
public String defaultSequence = "";
|
||||
|
||||
private HashMap<String, String> windowSeqPairs = new HashMap<>();
|
||||
|
||||
public AutoType() {}
|
||||
|
||||
public AutoType(Parcel in) {
|
||||
enabled = in.readByte() != 0;
|
||||
obfuscationOptions = in.readLong();
|
||||
defaultSequence = in.readString();
|
||||
windowSeqPairs = MemUtil.readStringParcelableMap(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeByte((byte) (enabled ? 1 : 0));
|
||||
dest.writeLong(obfuscationOptions);
|
||||
dest.writeString(defaultSequence);
|
||||
MemUtil.writeStringParcelableMap(dest, windowSeqPairs);
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<AutoType> CREATOR = new Parcelable.Creator<AutoType>() {
|
||||
@Override
|
||||
public AutoType createFromParcel(Parcel in) {
|
||||
return new AutoType(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AutoType[] newArray(int size) {
|
||||
return new AutoType[size];
|
||||
}
|
||||
};
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public AutoType clone() {
|
||||
AutoType auto;
|
||||
|
||||
@@ -19,9 +19,12 @@
|
||||
*/
|
||||
package com.kunzisoft.keepass.database;
|
||||
|
||||
import com.kunzisoft.keepass.database.security.ProtectedString;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import com.kunzisoft.keepass.database.security.ProtectedString;
|
||||
import com.kunzisoft.keepass.utils.MemUtil;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
@@ -32,7 +35,7 @@ import static com.kunzisoft.keepass.database.PwEntryV4.STR_TITLE;
|
||||
import static com.kunzisoft.keepass.database.PwEntryV4.STR_URL;
|
||||
import static com.kunzisoft.keepass.database.PwEntryV4.STR_USERNAME;
|
||||
|
||||
public class ExtraFields implements Serializable, Cloneable {
|
||||
public class ExtraFields implements Parcelable, Cloneable {
|
||||
|
||||
private Map<String, ProtectedString> fields;
|
||||
|
||||
@@ -40,6 +43,32 @@ public class ExtraFields implements Serializable, Cloneable {
|
||||
fields = new HashMap<>();
|
||||
}
|
||||
|
||||
public ExtraFields(Parcel in) {
|
||||
fields = MemUtil.readStringParcelableMap(in, ProtectedString.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
MemUtil.writeStringParcelableMap(dest, flags, fields);
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<ExtraFields> CREATOR = new Parcelable.Creator<ExtraFields>() {
|
||||
@Override
|
||||
public ExtraFields createFromParcel(Parcel in) {
|
||||
return new ExtraFields(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExtraFields[] newArray(int size) {
|
||||
return new ExtraFields[size];
|
||||
}
|
||||
};
|
||||
|
||||
public boolean containsCustomFields() {
|
||||
return !getCustomProtectedFields().keySet().isEmpty();
|
||||
}
|
||||
|
||||
@@ -19,10 +19,12 @@
|
||||
*/
|
||||
package com.kunzisoft.keepass.database;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import com.kunzisoft.keepass.app.App;
|
||||
import com.kunzisoft.keepass.utils.Types;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Arrays;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
@@ -33,15 +35,14 @@ import java.util.Date;
|
||||
* @author bpellin
|
||||
*
|
||||
*/
|
||||
public class PwDate implements Cloneable, Serializable {
|
||||
public class PwDate implements Cloneable, Parcelable {
|
||||
|
||||
private static final int DATE_SIZE = 5;
|
||||
|
||||
private boolean cDateBuilt = false;
|
||||
|
||||
private Date jDate;
|
||||
private boolean jDateBuilt = false;
|
||||
|
||||
private Date jDate;
|
||||
private byte[] cDate;
|
||||
private boolean cDateBuilt = false;
|
||||
|
||||
public static final Date NEVER_EXPIRE = getNeverExpire();
|
||||
public static final Date DEFAULT_DATE = getDefaultDate();
|
||||
@@ -93,6 +94,42 @@ public class PwDate implements Cloneable, Serializable {
|
||||
jDate = new Date();
|
||||
jDateBuilt = true;
|
||||
}
|
||||
|
||||
protected PwDate(Parcel in) {
|
||||
try {
|
||||
jDate = (Date) in.readSerializable();
|
||||
jDateBuilt = in.readByte() != 0;
|
||||
in.readByteArray(cDate);
|
||||
cDateBuilt = in.readByte() != 0;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeSerializable(jDate);
|
||||
dest.writeByte((byte) (jDateBuilt ? 1 : 0));
|
||||
dest.writeByteArray(cDate);
|
||||
dest.writeByte((byte) (cDateBuilt ? 1 : 0));
|
||||
}
|
||||
|
||||
public static final Creator<PwDate> CREATOR = new Creator<PwDate>() {
|
||||
@Override
|
||||
public PwDate createFromParcel(Parcel in) {
|
||||
return new PwDate(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PwDate[] newArray(int size) {
|
||||
return new PwDate[size];
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public PwDate clone() {
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
*/
|
||||
package com.kunzisoft.keepass.database;
|
||||
|
||||
import android.os.Parcel;
|
||||
|
||||
import com.kunzisoft.keepass.database.iterator.EntrySearchStringIterator;
|
||||
import com.kunzisoft.keepass.database.security.ProtectedString;
|
||||
|
||||
@@ -30,6 +32,19 @@ public abstract class PwEntry<Parent extends PwGroup> extends PwNode<Parent> {
|
||||
|
||||
protected UUID uuid = PwDatabase.UUID_ZERO;
|
||||
|
||||
public PwEntry() {}
|
||||
|
||||
public PwEntry(Parcel in) {
|
||||
super(in);
|
||||
uuid = (UUID) in.readSerializable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
super.writeToParcel(dest, flags);
|
||||
dest.writeSerializable(uuid);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void construct(Parent parent) {
|
||||
super.construct(parent);
|
||||
|
||||
@@ -42,6 +42,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
package com.kunzisoft.keepass.database;
|
||||
|
||||
import android.os.Parcel;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.UUID;
|
||||
|
||||
@@ -77,13 +79,11 @@ public class PwEntryV3 extends PwEntry<PwGroupV3> {
|
||||
|
||||
// TODO Parent ID to remove
|
||||
private int groupId;
|
||||
|
||||
private String title;
|
||||
private String username;
|
||||
private byte[] password;
|
||||
private String url;
|
||||
private String additional;
|
||||
|
||||
/** A string describing what is in pBinaryData */
|
||||
private String binaryDesc;
|
||||
private byte[] binaryData;
|
||||
@@ -97,6 +97,43 @@ public class PwEntryV3 extends PwEntry<PwGroupV3> {
|
||||
groupId = ((PwGroupIdV3) this.parent.getId()).getId(); // TODO remove
|
||||
}
|
||||
|
||||
public PwEntryV3(Parcel in) {
|
||||
super(in);
|
||||
groupId = in.readInt();
|
||||
title = in.readString();
|
||||
username = in.readString();
|
||||
in.readByteArray(password);
|
||||
url = in.readString();
|
||||
additional = in.readString();
|
||||
binaryDesc = in.readString();
|
||||
in.readByteArray(binaryData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
super.writeToParcel(dest, flags);
|
||||
dest.writeInt(groupId);
|
||||
dest.writeString(title);
|
||||
dest.writeString(username);
|
||||
dest.writeByteArray(password);
|
||||
dest.writeString(url);
|
||||
dest.writeString(additional);
|
||||
dest.writeString(binaryDesc);
|
||||
dest.writeByteArray(binaryData);
|
||||
}
|
||||
|
||||
public static final Creator<PwEntryV3> CREATOR = new Creator<PwEntryV3>() {
|
||||
@Override
|
||||
public PwEntryV3 createFromParcel(Parcel in) {
|
||||
return new PwEntryV3(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PwEntryV3[] newArray(int size) {
|
||||
return new PwEntryV3[size];
|
||||
}
|
||||
};
|
||||
|
||||
protected void updateWith(PwEntryV3 source) {
|
||||
super.assign(source);
|
||||
groupId = source.groupId;
|
||||
|
||||
@@ -19,8 +19,11 @@
|
||||
*/
|
||||
package com.kunzisoft.keepass.database;
|
||||
|
||||
import android.os.Parcel;
|
||||
|
||||
import com.kunzisoft.keepass.database.security.ProtectedBinary;
|
||||
import com.kunzisoft.keepass.database.security.ProtectedString;
|
||||
import com.kunzisoft.keepass.utils.MemUtil;
|
||||
import com.kunzisoft.keepass.utils.SprEngineV4;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -37,7 +40,7 @@ public class PwEntryV4 extends PwEntry<PwGroupV4> implements ITimeLogger {
|
||||
public static final String STR_URL = "URL";
|
||||
public static final String STR_NOTES = "Notes";
|
||||
|
||||
// To decode each field not serializable
|
||||
// To decode each field not parcelable
|
||||
private transient PwDatabaseV4 mDatabase = null;
|
||||
private transient boolean mDecodeRef = false;
|
||||
|
||||
@@ -45,7 +48,6 @@ public class PwEntryV4 extends PwEntry<PwGroupV4> implements ITimeLogger {
|
||||
private long usageCount = 0;
|
||||
private PwDate parentGroupLastMod = new PwDate();
|
||||
private Map<String, String> customData = new HashMap<>();
|
||||
|
||||
private ExtraFields fields = new ExtraFields();
|
||||
private HashMap<String, ProtectedBinary> binaries = new HashMap<>();
|
||||
private String foregroundColor = "";
|
||||
@@ -53,7 +55,6 @@ public class PwEntryV4 extends PwEntry<PwGroupV4> implements ITimeLogger {
|
||||
private String overrideURL = "";
|
||||
private AutoType autoType = new AutoType();
|
||||
private ArrayList<PwEntryV4> history = new ArrayList<>();
|
||||
|
||||
private String url = "";
|
||||
private String additional = "";
|
||||
private String tags = "";
|
||||
@@ -71,8 +72,8 @@ public class PwEntryV4 extends PwEntry<PwGroupV4> implements ITimeLogger {
|
||||
customIcon = source.customIcon;
|
||||
usageCount = source.usageCount;
|
||||
parentGroupLastMod = source.parentGroupLastMod;
|
||||
// TODO customData
|
||||
|
||||
customData.clear();
|
||||
customData.putAll(source.customData); // Add all custom elements in map
|
||||
fields = source.fields;
|
||||
binaries = source.binaries;
|
||||
foregroundColor = source.foregroundColor;
|
||||
@@ -80,12 +81,60 @@ public class PwEntryV4 extends PwEntry<PwGroupV4> implements ITimeLogger {
|
||||
overrideURL = source.overrideURL;
|
||||
autoType = source.autoType;
|
||||
history = source.history;
|
||||
|
||||
url = source.url;
|
||||
additional = source.additional;
|
||||
tags = source.tags;
|
||||
}
|
||||
|
||||
public PwEntryV4(Parcel in) {
|
||||
super(in);
|
||||
customIcon = in.readParcelable(PwIconCustom.class.getClassLoader());
|
||||
usageCount = in.readLong();
|
||||
parentGroupLastMod = in.readParcelable(PwDate.class.getClassLoader());
|
||||
customData = MemUtil.readStringParcelableMap(in);
|
||||
fields = in.readParcelable(ExtraFields.class.getClassLoader());
|
||||
binaries = MemUtil.readStringParcelableMap(in, ProtectedBinary.class);
|
||||
foregroundColor = in.readString();
|
||||
backgroupColor = in.readString();
|
||||
overrideURL = in.readString();
|
||||
autoType = in.readParcelable(AutoType.class.getClassLoader());
|
||||
history = in.readArrayList(PwEntryV4.class.getClassLoader()); // TODO verify
|
||||
url = in.readString();
|
||||
additional = in.readString();
|
||||
tags = in.readString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
super.writeToParcel(dest, flags);
|
||||
dest.writeParcelable(customIcon, flags);
|
||||
dest.writeLong(usageCount);
|
||||
dest.writeParcelable(parentGroupLastMod, flags);
|
||||
MemUtil.writeStringParcelableMap(dest, customData);
|
||||
dest.writeParcelable(fields, flags);
|
||||
MemUtil.writeStringParcelableMap(dest, flags, binaries);
|
||||
dest.writeString(foregroundColor);
|
||||
dest.writeString(backgroupColor);
|
||||
dest.writeString(overrideURL);
|
||||
dest.writeParcelable(autoType, flags);
|
||||
dest.writeList(history);
|
||||
dest.writeString(url);
|
||||
dest.writeString(additional);
|
||||
dest.writeString(tags);
|
||||
}
|
||||
|
||||
public static final Creator<PwEntryV4> CREATOR = new Creator<PwEntryV4>() {
|
||||
@Override
|
||||
public PwEntryV4 createFromParcel(Parcel in) {
|
||||
return new PwEntryV4(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PwEntryV4[] newArray(int size) {
|
||||
return new PwEntryV4[size];
|
||||
}
|
||||
};
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public PwEntryV4 clone() {
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
*/
|
||||
package com.kunzisoft.keepass.database;
|
||||
|
||||
import android.os.Parcel;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@@ -27,8 +29,24 @@ public abstract class PwGroup<Parent extends PwGroup, ChildGroup extends PwGroup
|
||||
|
||||
protected String name = "";
|
||||
|
||||
protected List<ChildGroup> childGroups = new ArrayList<>();
|
||||
protected List<ChildEntry> childEntries = new ArrayList<>();
|
||||
// TODO verify children not needed
|
||||
transient protected List<ChildGroup> childGroups = new ArrayList<>();
|
||||
transient protected List<ChildEntry> childEntries = new ArrayList<>();
|
||||
|
||||
protected PwGroup() {
|
||||
super();
|
||||
}
|
||||
|
||||
protected PwGroup(Parcel in) {
|
||||
super(in);
|
||||
name = in.readString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
super.writeToParcel(dest, flags);
|
||||
dest.writeString(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PwGroup clone() {
|
||||
|
||||
@@ -19,8 +19,20 @@
|
||||
*/
|
||||
package com.kunzisoft.keepass.database;
|
||||
|
||||
import java.io.Serializable;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
public abstract class PwGroupId implements Serializable {
|
||||
public abstract class PwGroupId implements Parcelable {
|
||||
|
||||
public PwGroupId() {}
|
||||
|
||||
public PwGroupId(Parcel in) {}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,13 +19,39 @@
|
||||
*/
|
||||
package com.kunzisoft.keepass.database;
|
||||
|
||||
import android.os.Parcel;
|
||||
|
||||
public class PwGroupIdV3 extends PwGroupId {
|
||||
|
||||
private int id;
|
||||
|
||||
public PwGroupIdV3(int i) {
|
||||
id = i;
|
||||
public PwGroupIdV3(int groupId) {
|
||||
super();
|
||||
this.id = groupId;
|
||||
}
|
||||
|
||||
public PwGroupIdV3(Parcel in) {
|
||||
super(in);
|
||||
id = in.readInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
super.writeToParcel(dest, flags);
|
||||
dest.writeInt(id);
|
||||
}
|
||||
|
||||
public static final Creator<PwGroupIdV3> CREATOR = new Creator<PwGroupIdV3>() {
|
||||
@Override
|
||||
public PwGroupIdV3 createFromParcel(Parcel in) {
|
||||
return new PwGroupIdV3(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PwGroupIdV3[] newArray(int size) {
|
||||
return new PwGroupIdV3[size];
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public boolean equals(Object compare) {
|
||||
|
||||
@@ -19,15 +19,42 @@
|
||||
*/
|
||||
package com.kunzisoft.keepass.database;
|
||||
|
||||
import android.os.Parcel;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class PwGroupIdV4 extends PwGroupId {
|
||||
|
||||
private UUID uuid;
|
||||
|
||||
public PwGroupIdV4(UUID u) {
|
||||
uuid = u;
|
||||
public PwGroupIdV4(UUID uuid) {
|
||||
super();
|
||||
this.uuid = uuid;
|
||||
}
|
||||
|
||||
|
||||
public PwGroupIdV4(Parcel in) {
|
||||
super(in);
|
||||
uuid = (UUID) in.readSerializable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
super.writeToParcel(dest, flags);
|
||||
dest.writeSerializable(uuid);
|
||||
}
|
||||
|
||||
public static final Creator<PwGroupIdV4> CREATOR = new Creator<PwGroupIdV4>() {
|
||||
@Override
|
||||
public PwGroupIdV4 createFromParcel(Parcel in) {
|
||||
return new PwGroupIdV4(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PwGroupIdV4[] newArray(int size) {
|
||||
return new PwGroupIdV4[size];
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public boolean equals(Object id) {
|
||||
if ( ! (id instanceof PwGroupIdV4) ) {
|
||||
@@ -36,12 +63,12 @@ public class PwGroupIdV4 extends PwGroupId {
|
||||
PwGroupIdV4 v4 = (PwGroupIdV4) id;
|
||||
return uuid.equals(v4.uuid);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return uuid.hashCode();
|
||||
}
|
||||
|
||||
|
||||
public UUID getId() {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
@@ -20,19 +20,13 @@
|
||||
|
||||
package com.kunzisoft.keepass.database;
|
||||
|
||||
/**
|
||||
* @author Brian Pellin <bpellin@gmail.com>
|
||||
* @author Naomaru Itoi <nao@phoneid.org>
|
||||
* @author Bill Zwicky <wrzwicky@pobox.com>
|
||||
* @author Dominik Reichl <dominik.reichl@t-online.de>
|
||||
*/
|
||||
import android.os.Parcel;
|
||||
|
||||
public class PwGroupV3 extends PwGroup<PwGroupV3, PwGroupV3, PwEntryV3> {
|
||||
|
||||
// for tree traversing
|
||||
private int groupId;
|
||||
|
||||
private int level = 0; // short
|
||||
|
||||
/** Used by KeePass internally, don't use */
|
||||
private int flags;
|
||||
|
||||
@@ -40,6 +34,33 @@ public class PwGroupV3 extends PwGroup<PwGroupV3, PwGroupV3, PwEntryV3> {
|
||||
super();
|
||||
}
|
||||
|
||||
public PwGroupV3(Parcel in) {
|
||||
super(in);
|
||||
groupId = in.readInt();
|
||||
level = in.readInt();
|
||||
flags = in.readInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
super.writeToParcel(dest, flags);
|
||||
dest.writeInt(groupId);
|
||||
dest.writeInt(level);
|
||||
dest.writeInt(flags);
|
||||
}
|
||||
|
||||
public static final Creator<PwGroupV3> CREATOR = new Creator<PwGroupV3>() {
|
||||
@Override
|
||||
public PwGroupV3 createFromParcel(Parcel in) {
|
||||
return new PwGroupV3(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PwGroupV3[] newArray(int size) {
|
||||
return new PwGroupV3[size];
|
||||
}
|
||||
};
|
||||
|
||||
public PwGroupV3(PwGroupV3 p) {
|
||||
construct(p);
|
||||
}
|
||||
|
||||
@@ -19,6 +19,10 @@
|
||||
*/
|
||||
package com.kunzisoft.keepass.database;
|
||||
|
||||
import android.os.Parcel;
|
||||
|
||||
import com.kunzisoft.keepass.utils.MemUtil;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
@@ -32,9 +36,7 @@ public class PwGroupV4 extends PwGroup<PwGroupV4, PwGroupV4, PwEntryV4> implemen
|
||||
private long usageCount = 0;
|
||||
private PwDate parentGroupLastMod = new PwDate();
|
||||
private Map<String, String> customData = new HashMap<>();
|
||||
|
||||
private boolean expires = false;
|
||||
|
||||
private String notes = "";
|
||||
private boolean isExpanded = true;
|
||||
private String defaultAutoTypeSequence = "";
|
||||
@@ -57,6 +59,53 @@ public class PwGroupV4 extends PwGroup<PwGroupV4, PwGroupV4, PwEntryV4> implemen
|
||||
this.icon = icon;
|
||||
}
|
||||
|
||||
public PwGroupV4(Parcel in) {
|
||||
super(in);
|
||||
uuid = (UUID) in.readSerializable();
|
||||
customIcon = in.readParcelable(PwIconCustom.class.getClassLoader());
|
||||
usageCount = in.readLong();
|
||||
parentGroupLastMod = in.readParcelable(PwDate.class.getClassLoader());
|
||||
customData = MemUtil.readStringParcelableMap(in);
|
||||
expires = in.readByte() != 0;
|
||||
notes = in.readString();
|
||||
isExpanded = in.readByte() != 0;
|
||||
defaultAutoTypeSequence = in.readString();
|
||||
byte autoTypeByte = in.readByte();
|
||||
enableAutoType = (autoTypeByte == -1) ? null : autoTypeByte != 0;
|
||||
byte enableSearchingByte = in.readByte();
|
||||
enableSearching = (enableSearchingByte == -1) ? null : enableSearchingByte != 0;
|
||||
lastTopVisibleEntry = (UUID) in.readSerializable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
super.writeToParcel(dest, flags);
|
||||
dest.writeSerializable(uuid);
|
||||
dest.writeParcelable(customIcon, flags);
|
||||
dest.writeLong(usageCount);
|
||||
dest.writeParcelable(parentGroupLastMod, flags);
|
||||
MemUtil.writeStringParcelableMap(dest, customData);
|
||||
dest.writeByte((byte) (expires ? 1 : 0));
|
||||
dest.writeString(notes);
|
||||
dest.writeByte((byte) (isExpanded ? 1 : 0));
|
||||
dest.writeString(defaultAutoTypeSequence);
|
||||
dest.writeByte((byte) (enableAutoType == null ? -1 : (enableAutoType ? 1 : 0)));
|
||||
dest.writeByte((byte) (enableAutoType == null ? -1 : (enableAutoType ? 1 : 0)));
|
||||
dest.writeSerializable(lastTopVisibleEntry);
|
||||
}
|
||||
|
||||
public static final Creator<PwGroupV4> CREATOR = new Creator<PwGroupV4>() {
|
||||
@Override
|
||||
public PwGroupV4 createFromParcel(Parcel in) {
|
||||
return new PwGroupV4(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PwGroupV4[] newArray(int size) {
|
||||
return new PwGroupV4[size];
|
||||
}
|
||||
};
|
||||
|
||||
protected void updateWith(PwGroupV4 source) {
|
||||
super.assign(source);
|
||||
uuid = source.uuid;
|
||||
|
||||
@@ -19,11 +19,21 @@
|
||||
*/
|
||||
package com.kunzisoft.keepass.database;
|
||||
|
||||
import java.io.Serializable;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
public abstract class PwIcon implements Serializable {
|
||||
public abstract class PwIcon implements Parcelable {
|
||||
|
||||
public boolean isMetaStreamIcon() {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected PwIcon() {}
|
||||
|
||||
protected PwIcon(Parcel in) {}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
*/
|
||||
package com.kunzisoft.keepass.database;
|
||||
|
||||
import android.os.Parcel;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class PwIconCustom extends PwIcon {
|
||||
@@ -27,16 +29,42 @@ public class PwIconCustom extends PwIcon {
|
||||
public final UUID uuid;
|
||||
public byte[] imageData;
|
||||
|
||||
public PwIconCustom(UUID u, byte[] data) {
|
||||
uuid = u;
|
||||
imageData = data;
|
||||
public PwIconCustom(UUID uuid, byte[] data) {
|
||||
super();
|
||||
this.uuid = uuid;
|
||||
this.imageData = data;
|
||||
}
|
||||
|
||||
public PwIconCustom(PwIconCustom icon) {
|
||||
super();
|
||||
uuid = icon.uuid;
|
||||
imageData = icon.imageData;
|
||||
}
|
||||
|
||||
protected PwIconCustom(Parcel in) {
|
||||
super(in);
|
||||
uuid = (UUID) in.readSerializable();
|
||||
in.readByteArray(imageData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeSerializable(uuid);
|
||||
dest.writeByteArray(imageData);
|
||||
}
|
||||
|
||||
public static final Creator<PwIconCustom> CREATOR = new Creator<PwIconCustom>() {
|
||||
@Override
|
||||
public PwIconCustom createFromParcel(Parcel in) {
|
||||
return new PwIconCustom(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PwIconCustom[] newArray(int size) {
|
||||
return new PwIconCustom[size];
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
@@ -55,10 +83,7 @@ public class PwIconCustom extends PwIcon {
|
||||
return false;
|
||||
PwIconCustom other = (PwIconCustom) obj;
|
||||
if (uuid == null) {
|
||||
if (other.uuid != null)
|
||||
return false;
|
||||
} else if (!uuid.equals(other.uuid))
|
||||
return false;
|
||||
return true;
|
||||
return other.uuid == null;
|
||||
} else return uuid.equals(other.uuid);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
*/
|
||||
package com.kunzisoft.keepass.database;
|
||||
|
||||
import android.os.Parcel;
|
||||
|
||||
public class PwIconStandard extends PwIcon {
|
||||
public final int iconId;
|
||||
|
||||
@@ -34,6 +36,28 @@ public class PwIconStandard extends PwIcon {
|
||||
this.iconId = icon.iconId;
|
||||
}
|
||||
|
||||
protected PwIconStandard(Parcel in) {
|
||||
super(in);
|
||||
iconId = in.readInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeInt(iconId);
|
||||
}
|
||||
|
||||
public static final Creator<PwIconStandard> CREATOR = new Creator<PwIconStandard>() {
|
||||
@Override
|
||||
public PwIconStandard createFromParcel(Parcel in) {
|
||||
return new PwIconStandard(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PwIconStandard[] newArray(int size) {
|
||||
return new PwIconStandard[size];
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public boolean isMetaStreamIcon() {
|
||||
return iconId == 0;
|
||||
|
||||
@@ -20,33 +20,69 @@
|
||||
*/
|
||||
package com.kunzisoft.keepass.database;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import java.io.Serializable;
|
||||
import com.kunzisoft.keepass.app.App;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
|
||||
/**
|
||||
* Abstract class who manage Groups and Entries
|
||||
*/
|
||||
public abstract class PwNode<Parent extends PwGroup> implements ISmallTimeLogger, Serializable, Cloneable {
|
||||
public abstract class PwNode<Parent extends PwGroup> implements ISmallTimeLogger, Parcelable, Cloneable {
|
||||
|
||||
protected Parent parent = null;
|
||||
|
||||
protected PwIconStandard icon = new PwIconStandard(0);
|
||||
|
||||
protected PwDate creation = new PwDate();
|
||||
protected PwDate lastMod = new PwDate();
|
||||
protected PwDate lastAccess = new PwDate();
|
||||
protected PwDate expireDate = PwDate.PW_NEVER_EXPIRE;
|
||||
|
||||
protected PwNode() {}
|
||||
|
||||
protected PwNode(Parcel in) {
|
||||
// TODO better technique ?
|
||||
try {
|
||||
PwGroupId pwGroupId = in.readParcelable(PwGroupId.class.getClassLoader());
|
||||
parent = (Parent) App.getDB().getPwDatabase().getGroupByGroupId(pwGroupId);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
icon = in.readParcelable(PwIconStandard.class.getClassLoader());
|
||||
creation = in.readParcelable(PwDate.class.getClassLoader());
|
||||
lastMod = in.readParcelable(PwDate.class.getClassLoader());
|
||||
lastAccess = in.readParcelable(PwDate.class.getClassLoader());
|
||||
expireDate = in.readParcelable(PwDate.class.getClassLoader());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
PwGroupId parentId = null;
|
||||
if (parent != null)
|
||||
parentId = parent.getId();
|
||||
dest.writeParcelable(parentId, flags);
|
||||
|
||||
dest.writeParcelable(icon, flags);
|
||||
dest.writeParcelable(creation, flags);
|
||||
dest.writeParcelable(lastMod, flags);
|
||||
dest.writeParcelable(lastAccess, flags);
|
||||
dest.writeParcelable(expireDate, flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected void construct(Parent parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
protected void assign(PwNode<Parent> source) {
|
||||
this.parent = source.parent;
|
||||
|
||||
this.icon = source.icon;
|
||||
|
||||
this.creation = source.creation;
|
||||
this.lastMod = source.lastMod;
|
||||
this.lastAccess = source.lastAccess;
|
||||
@@ -59,9 +95,7 @@ public abstract class PwNode<Parent extends PwGroup> implements ISmallTimeLogger
|
||||
try {
|
||||
newNode = (PwNode) super.clone();
|
||||
// newNode.parent stay the same in copy
|
||||
|
||||
newNode.icon = new PwIconStandard(this.icon);
|
||||
|
||||
newNode.creation = creation.clone();
|
||||
newNode.lastMod = lastMod.clone();
|
||||
newNode.lastAccess = lastAccess.clone();
|
||||
|
||||
@@ -19,15 +19,17 @@
|
||||
*/
|
||||
package com.kunzisoft.keepass.database.security;
|
||||
|
||||
import java.io.Serializable;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class ProtectedBinary implements Serializable {
|
||||
public class ProtectedBinary implements Parcelable {
|
||||
|
||||
public final static ProtectedBinary EMPTY = new ProtectedBinary();
|
||||
|
||||
private byte[] data;
|
||||
|
||||
private boolean protect;
|
||||
private byte[] data;
|
||||
|
||||
public boolean isProtected() {
|
||||
return protect;
|
||||
@@ -37,21 +39,22 @@ public class ProtectedBinary implements Serializable {
|
||||
if (data == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return data.length;
|
||||
}
|
||||
|
||||
public ProtectedBinary() {
|
||||
this(false, new byte[0]);
|
||||
|
||||
}
|
||||
|
||||
public ProtectedBinary(boolean enableProtection, byte[] data) {
|
||||
protect = enableProtection;
|
||||
this.protect = enableProtection;
|
||||
this.data = data;
|
||||
|
||||
}
|
||||
|
||||
|
||||
public ProtectedBinary(Parcel in) {
|
||||
protect = in.readByte() != 0;
|
||||
in.readByteArray(data);
|
||||
}
|
||||
|
||||
// TODO: replace the byte[] with something like ByteBuffer to make the return
|
||||
// value immutable, so we don't have to worry about making deep copies
|
||||
@@ -63,4 +66,27 @@ public class ProtectedBinary implements Serializable {
|
||||
return (protect == rhs.protect) && Arrays.equals(data, rhs.data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeByte((byte) (protect ? 1 : 0));
|
||||
dest.writeByteArray(data);
|
||||
}
|
||||
|
||||
public static final Creator<ProtectedBinary> CREATOR = new Creator<ProtectedBinary>() {
|
||||
@Override
|
||||
public ProtectedBinary createFromParcel(Parcel in) {
|
||||
return new ProtectedBinary(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProtectedBinary[] newArray(int size) {
|
||||
return new ProtectedBinary[size];
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -19,38 +19,66 @@
|
||||
*/
|
||||
package com.kunzisoft.keepass.database.security;
|
||||
|
||||
import java.io.Serializable;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
public class ProtectedString implements Parcelable {
|
||||
|
||||
public class ProtectedString implements Serializable {
|
||||
|
||||
private String string;
|
||||
private boolean protect;
|
||||
|
||||
public boolean isProtected() {
|
||||
return protect;
|
||||
}
|
||||
|
||||
public int length() {
|
||||
if (string == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return string.length();
|
||||
}
|
||||
private String string;
|
||||
|
||||
public ProtectedString() {
|
||||
this(false, "");
|
||||
}
|
||||
|
||||
public ProtectedString(ProtectedString toCopy) {
|
||||
this.string = toCopy.string;
|
||||
this.protect = toCopy.protect;
|
||||
this.string = toCopy.string;
|
||||
}
|
||||
|
||||
public ProtectedString(boolean enableProtection, String string) {
|
||||
protect = enableProtection;
|
||||
this.protect = enableProtection;
|
||||
this.string = string;
|
||||
|
||||
}
|
||||
|
||||
public ProtectedString(Parcel in) {
|
||||
protect = in.readByte() != 0;
|
||||
string = in.readString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeByte((byte) (protect ? 1 : 0));
|
||||
dest.writeString(string);
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<ProtectedString> CREATOR = new Parcelable.Creator<ProtectedString>() {
|
||||
@Override
|
||||
public ProtectedString createFromParcel(Parcel in) {
|
||||
return new ProtectedString(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProtectedString[] newArray(int size) {
|
||||
return new ProtectedString[size];
|
||||
}
|
||||
};
|
||||
|
||||
public boolean isProtected() {
|
||||
return protect;
|
||||
}
|
||||
|
||||
public int length() {
|
||||
if (string == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return string.length();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -79,7 +79,7 @@ public class GroupEditDialogFragment extends DialogFragment
|
||||
public static GroupEditDialogFragment build(PwNode group) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString(KEY_NAME, group.getDisplayTitle());
|
||||
bundle.putSerializable(KEY_ICON_ID, group.getIcon());
|
||||
bundle.putParcelable(KEY_ICON_ID, group.getIcon());
|
||||
bundle.putInt(KEY_ACTION_ID, UPDATE.ordinal());
|
||||
GroupEditDialogFragment fragment = new GroupEditDialogFragment();
|
||||
fragment.setArguments(bundle);
|
||||
@@ -125,7 +125,7 @@ public class GroupEditDialogFragment extends DialogFragment
|
||||
&& savedInstanceState.containsKey(KEY_ICON_ID)) {
|
||||
editGroupDialogAction = getActionFromOrdinal(savedInstanceState.getInt(KEY_ACTION_ID));
|
||||
nameGroup = savedInstanceState.getString(KEY_NAME);
|
||||
iconGroup = (PwIcon) savedInstanceState.getSerializable(KEY_ICON_ID);
|
||||
iconGroup = savedInstanceState.getParcelable(KEY_ICON_ID);
|
||||
|
||||
} else {
|
||||
|
||||
@@ -137,7 +137,7 @@ public class GroupEditDialogFragment extends DialogFragment
|
||||
&& getArguments().containsKey(KEY_NAME)
|
||||
&& getArguments().containsKey(KEY_ICON_ID)) {
|
||||
nameGroup = getArguments().getString(KEY_NAME);
|
||||
iconGroup = (PwIcon) getArguments().getSerializable(KEY_ICON_ID);
|
||||
iconGroup = getArguments().getParcelable(KEY_ICON_ID);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -206,7 +206,7 @@ public class GroupEditDialogFragment extends DialogFragment
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
outState.putInt(KEY_ACTION_ID, editGroupDialogAction.ordinal());
|
||||
outState.putString(KEY_NAME, nameGroup);
|
||||
outState.putSerializable(KEY_ICON_ID, iconGroup);
|
||||
outState.putParcelable(KEY_ICON_ID, iconGroup);
|
||||
super.onSaveInstanceState(outState);
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.Log;
|
||||
|
||||
import com.kunzisoft.keepass.activities.ReadOnlyHelper;
|
||||
import com.kunzisoft.keepass.app.App;
|
||||
import com.kunzisoft.keepass.settings.PreferencesUtil;
|
||||
import com.kunzisoft.keepass.stylish.StylishActivity;
|
||||
@@ -45,6 +46,7 @@ public abstract class LockingActivity extends StylishActivity {
|
||||
private LockReceiver lockReceiver;
|
||||
private boolean exitLock;
|
||||
|
||||
protected boolean readOnly;
|
||||
|
||||
/**
|
||||
* Called to start a record time,
|
||||
@@ -72,6 +74,9 @@ public abstract class LockingActivity extends StylishActivity {
|
||||
lockReceiver = null;
|
||||
|
||||
exitLock = false;
|
||||
|
||||
readOnly = false;
|
||||
readOnly = ReadOnlyHelper.retrieveReadOnlyFromInstanceStateOrIntent(savedInstanceState, getIntent());
|
||||
}
|
||||
|
||||
public static void checkShutdown(Activity activity) {
|
||||
@@ -116,6 +121,12 @@ public abstract class LockingActivity extends StylishActivity {
|
||||
TimeoutHelper.recordTime(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle outState) {
|
||||
ReadOnlyHelper.onSaveInstanceState(outState, readOnly);
|
||||
super.onSaveInstanceState(outState);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
|
||||
@@ -239,11 +239,13 @@ public class NotificationCopyingService extends Service {
|
||||
}
|
||||
countingDownTask = null;
|
||||
notificationManager.cancel(myNotificationId);
|
||||
try {
|
||||
clipboardHelper.cleanClipboard();
|
||||
} catch (SamsungClipboardException e) {
|
||||
Log.e(TAG, "Clipboard can't be cleaned", e);
|
||||
}
|
||||
// Clean password only if no next field
|
||||
if (nextFields.size() <= 0)
|
||||
try {
|
||||
clipboardHelper.cleanClipboard();
|
||||
} catch (SamsungClipboardException e) {
|
||||
Log.e(TAG, "Clipboard can't be cleaned", e);
|
||||
}
|
||||
});
|
||||
countingDownTask.start();
|
||||
|
||||
|
||||
@@ -55,9 +55,9 @@ import android.widget.Toast;
|
||||
import com.getkeepsafe.taptargetview.TapTarget;
|
||||
import com.getkeepsafe.taptargetview.TapTargetView;
|
||||
import com.kunzisoft.keepass.R;
|
||||
import com.kunzisoft.keepass.activities.ReadOnlyHelper;
|
||||
import com.kunzisoft.keepass.activities.GroupActivity;
|
||||
import com.kunzisoft.keepass.selection.EntrySelectionHelper;
|
||||
import com.kunzisoft.keepass.lock.LockingActivity;
|
||||
import com.kunzisoft.keepass.activities.IntentBuildLauncher;
|
||||
import com.kunzisoft.keepass.app.App;
|
||||
import com.kunzisoft.keepass.autofill.AutofillHelper;
|
||||
import com.kunzisoft.keepass.compat.ClipDataCompat;
|
||||
@@ -69,6 +69,8 @@ import com.kunzisoft.keepass.fileselect.KeyFileHelper;
|
||||
import com.kunzisoft.keepass.fingerprint.FingerPrintAnimatedVector;
|
||||
import com.kunzisoft.keepass.fingerprint.FingerPrintExplanationDialog;
|
||||
import com.kunzisoft.keepass.fingerprint.FingerPrintHelper;
|
||||
import com.kunzisoft.keepass.lock.LockingActivity;
|
||||
import com.kunzisoft.keepass.selection.EntrySelectionHelper;
|
||||
import com.kunzisoft.keepass.settings.PreferencesUtil;
|
||||
import com.kunzisoft.keepass.stylish.StylishActivity;
|
||||
import com.kunzisoft.keepass.tasks.ProgressTaskDialogFragment;
|
||||
@@ -124,6 +126,8 @@ public class PasswordActivity extends StylishActivity
|
||||
private CompoundButton checkboxDefaultDatabaseView;
|
||||
private CompoundButton.OnCheckedChangeListener enableButtonOncheckedChangeListener;
|
||||
|
||||
private boolean readOnly;
|
||||
|
||||
private DefaultCheckChange defaultCheckChange;
|
||||
private ValidateButtonViewClickListener validateButtonViewClickListener;
|
||||
|
||||
@@ -139,16 +143,23 @@ public class PasswordActivity extends StylishActivity
|
||||
}
|
||||
|
||||
public static void launch(
|
||||
Activity act,
|
||||
Activity activity,
|
||||
String fileName,
|
||||
String keyFile) throws FileNotFoundException {
|
||||
verifyFileNameUriFromLaunch(fileName);
|
||||
|
||||
Intent intent = new Intent(act, PasswordActivity.class);
|
||||
buildAndLaunchIntent(activity, fileName, keyFile, (intent) -> {
|
||||
// only to avoid visible flickering when redirecting
|
||||
activity.startActivityForResult(intent, RESULT_CANCELED);
|
||||
});
|
||||
}
|
||||
|
||||
private static void buildAndLaunchIntent(Activity activity, String fileName, String keyFile,
|
||||
IntentBuildLauncher intentBuildLauncher) {
|
||||
Intent intent = new Intent(activity, PasswordActivity.class);
|
||||
intent.putExtra(UriIntentInitTask.KEY_FILENAME, fileName);
|
||||
intent.putExtra(UriIntentInitTask.KEY_KEYFILE, keyFile);
|
||||
// only to avoid visible flickering when redirecting
|
||||
act.startActivityForResult(intent, RESULT_CANCELED);
|
||||
intentBuildLauncher.startActivityForResult(intent);
|
||||
}
|
||||
|
||||
public static void launchForKeyboardResult(
|
||||
@@ -158,17 +169,16 @@ public class PasswordActivity extends StylishActivity
|
||||
}
|
||||
|
||||
public static void launchForKeyboardResult(
|
||||
Activity act,
|
||||
Activity activity,
|
||||
String fileName,
|
||||
String keyFile) throws FileNotFoundException {
|
||||
verifyFileNameUriFromLaunch(fileName);
|
||||
|
||||
Intent intent = new Intent(act, PasswordActivity.class);
|
||||
intent.putExtra(UriIntentInitTask.KEY_FILENAME, fileName);
|
||||
intent.putExtra(UriIntentInitTask.KEY_KEYFILE, keyFile);
|
||||
EntrySelectionHelper.addEntrySelectionModeExtraInIntent(intent);
|
||||
// only to avoid visible flickering when redirecting
|
||||
act.startActivityForResult(intent, EntrySelectionHelper.ENTRY_SELECTION_RESPONSE_REQUEST_CODE);
|
||||
buildAndLaunchIntent(activity, fileName, keyFile, (intent) -> {
|
||||
EntrySelectionHelper.addEntrySelectionModeExtraInIntent(intent);
|
||||
// only to avoid visible flickering when redirecting
|
||||
activity.startActivityForResult(intent, EntrySelectionHelper.ENTRY_SELECTION_RESPONSE_REQUEST_CODE);
|
||||
});
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||
@@ -181,20 +191,19 @@ public class PasswordActivity extends StylishActivity
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||
public static void launchForAutofillResult(
|
||||
Activity act,
|
||||
Activity activity,
|
||||
String fileName,
|
||||
String keyFile,
|
||||
AssistStructure assistStructure) throws FileNotFoundException {
|
||||
verifyFileNameUriFromLaunch(fileName);
|
||||
|
||||
if ( assistStructure != null ) {
|
||||
Intent intent = new Intent(act, PasswordActivity.class);
|
||||
intent.putExtra(UriIntentInitTask.KEY_FILENAME, fileName);
|
||||
intent.putExtra(UriIntentInitTask.KEY_KEYFILE, keyFile);
|
||||
AutofillHelper.addAssistStructureExtraInIntent(intent, assistStructure);
|
||||
act.startActivityForResult(intent, AutofillHelper.AUTOFILL_RESPONSE_REQUEST_CODE);
|
||||
buildAndLaunchIntent(activity, fileName, keyFile, (intent) -> {
|
||||
AutofillHelper.addAssistStructureExtraInIntent(intent, assistStructure);
|
||||
activity.startActivityForResult(intent, AutofillHelper.AUTOFILL_RESPONSE_REQUEST_CODE);
|
||||
});
|
||||
} else {
|
||||
launch(act, fileName, keyFile);
|
||||
launch(activity, fileName, keyFile);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -276,6 +285,8 @@ public class PasswordActivity extends StylishActivity
|
||||
checkboxKeyfileView = findViewById(R.id.keyfile_checkox);
|
||||
checkboxDefaultDatabaseView = findViewById(R.id.default_database);
|
||||
|
||||
readOnly = ReadOnlyHelper.retrieveReadOnlyFromInstanceStateOrPreference(this, savedInstanceState);
|
||||
|
||||
View browseView = findViewById(R.id.browse_button);
|
||||
keyFileHelper = new KeyFileHelper(PasswordActivity.this);
|
||||
browseView.setOnClickListener(keyFileHelper.getOpenFileOnClickViewListener());
|
||||
@@ -326,8 +337,6 @@ public class PasswordActivity extends StylishActivity
|
||||
autofillHelper = new AutofillHelper();
|
||||
autofillHelper.retrieveAssistStructure(getIntent());
|
||||
}
|
||||
|
||||
checkAndPerformedEducation();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -380,11 +389,17 @@ public class PasswordActivity extends StylishActivity
|
||||
.execute(getIntent());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle outState) {
|
||||
ReadOnlyHelper.onSaveInstanceState(outState, readOnly);
|
||||
super.onSaveInstanceState(outState);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check and display learning views
|
||||
* Displays the explanation for a database opening with fingerprints if available
|
||||
*/
|
||||
private void checkAndPerformedEducation() {
|
||||
private void checkAndPerformedEducation(Menu menu) {
|
||||
if (PreferencesUtil.isEducationScreensEnabled(this)) {
|
||||
|
||||
if (!PreferencesUtil.isEducationUnlockPerformed(this)) {
|
||||
@@ -414,7 +429,39 @@ public class PasswordActivity extends StylishActivity
|
||||
}
|
||||
});
|
||||
// TODO make a period for donation
|
||||
PreferencesUtil.saveEducationPreference(PasswordActivity.this, R.string.education_unlock_key);
|
||||
PreferencesUtil.saveEducationPreference(PasswordActivity.this,
|
||||
R.string.education_unlock_key);
|
||||
|
||||
} else if (!PreferencesUtil.isEducationReadOnlyPerformed(this)) {
|
||||
|
||||
try {
|
||||
TapTargetView.showFor(this,
|
||||
TapTarget.forToolbarMenuItem(toolbar, R.id.menu_open_file_read_mode_key,
|
||||
getString(R.string.education_read_only_title),
|
||||
getString(R.string.education_read_only_summary))
|
||||
.textColorInt(Color.WHITE)
|
||||
.tintTarget(true)
|
||||
.cancelable(true),
|
||||
new TapTargetView.Listener() {
|
||||
@Override
|
||||
public void onTargetClick(TapTargetView view) {
|
||||
super.onTargetClick(view);
|
||||
MenuItem editItem = menu.findItem(R.id.menu_open_file_read_mode_key);
|
||||
onOptionsItemSelected(editItem);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOuterCircleClick(TapTargetView view) {
|
||||
super.onOuterCircleClick(view);
|
||||
view.dismiss(false);
|
||||
}
|
||||
});
|
||||
PreferencesUtil.saveEducationPreference(this,
|
||||
R.string.education_read_only_key);
|
||||
} catch (Exception e) {
|
||||
// If icon not visible
|
||||
Log.w(TAG, "Can't performed education for entry's edition");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -953,14 +1000,14 @@ public class PasswordActivity extends StylishActivity
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
|
||||
assistStructure = autofillHelper.getAssistStructure();
|
||||
if (assistStructure != null) {
|
||||
GroupActivity.launchForAutofillResult(PasswordActivity.this, assistStructure);
|
||||
GroupActivity.launchForAutofillResult(PasswordActivity.this, assistStructure, readOnly);
|
||||
}
|
||||
}
|
||||
if (assistStructure == null) {
|
||||
if (entrySelectionMode) {
|
||||
GroupActivity.launchForKeyboardResult(PasswordActivity.this);
|
||||
GroupActivity.launchForKeyboardResult(PasswordActivity.this, readOnly);
|
||||
} else {
|
||||
GroupActivity.launch(PasswordActivity.this);
|
||||
GroupActivity.launch(PasswordActivity.this, readOnly);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -968,16 +1015,35 @@ public class PasswordActivity extends StylishActivity
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
MenuInflater inflater = getMenuInflater();
|
||||
// Read menu
|
||||
inflater.inflate(R.menu.open_file, menu);
|
||||
changeOpenFileReadIcon(menu.findItem(R.id.menu_open_file_read_mode_key));
|
||||
|
||||
MenuUtil.defaultMenuInflater(inflater, menu);
|
||||
|
||||
// Fingerprint menu
|
||||
if (!fingerprintMustBeConfigured
|
||||
&& prefsNoBackup.contains(getPreferenceKeyValue()) )
|
||||
inflater.inflate(R.menu.fingerprint, menu);
|
||||
|
||||
super.onCreateOptionsMenu(menu);
|
||||
|
||||
// Show education views
|
||||
new Handler().post(() -> checkAndPerformedEducation(menu));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void changeOpenFileReadIcon(MenuItem togglePassword) {
|
||||
if ( readOnly ) {
|
||||
togglePassword.setTitle(R.string.menu_file_selection_read_only);
|
||||
togglePassword.setIcon(R.drawable.ic_read_only_white_24dp);
|
||||
} else {
|
||||
togglePassword.setTitle(R.string.menu_open_file_read_and_write);
|
||||
togglePassword.setIcon(R.drawable.ic_read_write_white_24dp);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
|
||||
@@ -985,6 +1051,10 @@ public class PasswordActivity extends StylishActivity
|
||||
case android.R.id.home:
|
||||
finish();
|
||||
break;
|
||||
case R.id.menu_open_file_read_mode_key:
|
||||
readOnly = !readOnly;
|
||||
changeOpenFileReadIcon(item);
|
||||
break;
|
||||
case R.id.menu_fingerprint_remove_key:
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
deleteEntryKey();
|
||||
|
||||
@@ -30,8 +30,7 @@ import android.view.View;
|
||||
|
||||
import com.kunzisoft.keepass.R;
|
||||
import com.kunzisoft.keepass.activities.ListNodesActivity;
|
||||
import com.kunzisoft.keepass.app.App;
|
||||
import com.kunzisoft.keepass.database.Database;
|
||||
import com.kunzisoft.keepass.activities.ListNodesFragment;
|
||||
import com.kunzisoft.keepass.database.PwGroup;
|
||||
import com.kunzisoft.keepass.utils.MenuUtil;
|
||||
|
||||
@@ -67,14 +66,22 @@ public class SearchResultsActivity extends ListNodesActivity {
|
||||
}
|
||||
}
|
||||
|
||||
@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) {
|
||||
Database mDb = App.getDB();
|
||||
// Likely the app has been killed exit the activity
|
||||
if ( ! mDb.getLoaded() ) {
|
||||
if ( ! database.getLoaded() ) {
|
||||
finish();
|
||||
}
|
||||
return mDb.search(getSearchStr(getIntent()).trim());
|
||||
return database.search(getSearchStr(getIntent()).trim());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -43,6 +43,7 @@ import android.widget.Toast;
|
||||
|
||||
import com.kunzisoft.keepass.BuildConfig;
|
||||
import com.kunzisoft.keepass.R;
|
||||
import com.kunzisoft.keepass.activities.ReadOnlyHelper;
|
||||
import com.kunzisoft.keepass.app.App;
|
||||
import com.kunzisoft.keepass.database.Database;
|
||||
import com.kunzisoft.keepass.dialogs.ProFeatureDialogFragment;
|
||||
@@ -72,6 +73,9 @@ public class NestedSettingsFragment extends PreferenceFragmentCompat
|
||||
|
||||
private static final int REQUEST_CODE_AUTOFILL = 5201;
|
||||
|
||||
private Database database;
|
||||
private boolean databaseReadOnly;
|
||||
|
||||
private int count = 0;
|
||||
|
||||
private Preference roundPref;
|
||||
@@ -79,14 +83,24 @@ public class NestedSettingsFragment extends PreferenceFragmentCompat
|
||||
private Preference parallelismPref;
|
||||
|
||||
public static NestedSettingsFragment newInstance(Screen key) {
|
||||
return newInstance(key, ReadOnlyHelper.READ_ONLY_DEFAULT);
|
||||
}
|
||||
|
||||
public static NestedSettingsFragment newInstance(Screen key, boolean databaseReadOnly) {
|
||||
NestedSettingsFragment fragment = new NestedSettingsFragment();
|
||||
// supply arguments to bundle.
|
||||
Bundle args = new Bundle();
|
||||
args.putInt(TAG_KEY, key.ordinal());
|
||||
ReadOnlyHelper.putReadOnlyInBundle(args, databaseReadOnly);
|
||||
fragment.setArguments(args);
|
||||
return fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
@@ -110,6 +124,10 @@ public class NestedSettingsFragment extends PreferenceFragmentCompat
|
||||
if (getArguments() != null)
|
||||
key = getArguments().getInt(TAG_KEY);
|
||||
|
||||
database = App.getDB();
|
||||
databaseReadOnly = ReadOnlyHelper.retrieveReadOnlyFromInstanceStateOrArguments(savedInstanceState, getArguments());
|
||||
databaseReadOnly = database.isReadOnly() || databaseReadOnly;
|
||||
|
||||
// Load the preferences from an XML resource
|
||||
switch (Screen.values()[key]) {
|
||||
case APPLICATION:
|
||||
@@ -306,23 +324,22 @@ public class NestedSettingsFragment extends PreferenceFragmentCompat
|
||||
case DATABASE:
|
||||
setPreferencesFromResource(R.xml.database_preferences, rootKey);
|
||||
|
||||
Database db = App.getDB();
|
||||
if (db.getLoaded()) {
|
||||
if (database.getLoaded()) {
|
||||
|
||||
PreferenceCategory dbGeneralPrefCategory = (PreferenceCategory) findPreference(getString(R.string.database_general_key));
|
||||
|
||||
// Db name
|
||||
Preference dbNamePref = findPreference(getString(R.string.database_name_key));
|
||||
if ( db.containsName() ) {
|
||||
dbNamePref.setSummary(db.getName());
|
||||
if ( database.containsName() ) {
|
||||
dbNamePref.setSummary(database.getName());
|
||||
} else {
|
||||
dbGeneralPrefCategory.removePreference(dbNamePref);
|
||||
}
|
||||
|
||||
// Db description
|
||||
Preference dbDescriptionPref = findPreference(getString(R.string.database_description_key));
|
||||
if ( db.containsDescription() ) {
|
||||
dbDescriptionPref.setSummary(db.getDescription());
|
||||
if ( database.containsDescription() ) {
|
||||
dbDescriptionPref.setSummary(database.getDescription());
|
||||
} else {
|
||||
dbGeneralPrefCategory.removePreference(dbDescriptionPref);
|
||||
}
|
||||
@@ -331,9 +348,9 @@ public class NestedSettingsFragment extends PreferenceFragmentCompat
|
||||
SwitchPreference recycleBinPref = (SwitchPreference) findPreference(getString(R.string.recycle_bin_key));
|
||||
// TODO Recycle
|
||||
dbGeneralPrefCategory.removePreference(recycleBinPref); // To delete
|
||||
if (db.isRecycleBinAvailable()) {
|
||||
if (database.isRecycleBinAvailable()) {
|
||||
|
||||
recycleBinPref.setChecked(db.isRecycleBinEnabled());
|
||||
recycleBinPref.setChecked(database.isRecycleBinEnabled());
|
||||
recycleBinPref.setEnabled(false);
|
||||
} else {
|
||||
dbGeneralPrefCategory.removePreference(recycleBinPref);
|
||||
@@ -341,27 +358,27 @@ public class NestedSettingsFragment extends PreferenceFragmentCompat
|
||||
|
||||
// Version
|
||||
Preference dbVersionPref = findPreference(getString(R.string.database_version_key));
|
||||
dbVersionPref.setSummary(db.getVersion());
|
||||
dbVersionPref.setSummary(database.getVersion());
|
||||
|
||||
// Encryption Algorithm
|
||||
Preference algorithmPref = findPreference(getString(R.string.encryption_algorithm_key));
|
||||
algorithmPref.setSummary(db.getEncryptionAlgorithmName(getResources()));
|
||||
algorithmPref.setSummary(database.getEncryptionAlgorithmName(getResources()));
|
||||
|
||||
// Key derivation function
|
||||
Preference kdfPref = findPreference(getString(R.string.key_derivation_function_key));
|
||||
kdfPref.setSummary(db.getKeyDerivationName(getResources()));
|
||||
kdfPref.setSummary(database.getKeyDerivationName(getResources()));
|
||||
|
||||
// Round encryption
|
||||
roundPref = findPreference(getString(R.string.transform_rounds_key));
|
||||
roundPref.setSummary(db.getNumberKeyEncryptionRoundsAsString());
|
||||
roundPref.setSummary(database.getNumberKeyEncryptionRoundsAsString());
|
||||
|
||||
// Memory Usage
|
||||
memoryPref = findPreference(getString(R.string.memory_usage_key));
|
||||
memoryPref.setSummary(db.getMemoryUsageAsString());
|
||||
memoryPref.setSummary(database.getMemoryUsageAsString());
|
||||
|
||||
// Parallelism
|
||||
parallelismPref = findPreference(getString(R.string.parallelism_key));
|
||||
parallelismPref.setSummary(db.getParallelismAsString());
|
||||
parallelismPref.setSummary(database.getParallelismAsString());
|
||||
|
||||
} else {
|
||||
Log.e(getClass().getName(), "Database isn't ready");
|
||||
@@ -480,18 +497,16 @@ public class NestedSettingsFragment extends PreferenceFragmentCompat
|
||||
|
||||
assert getFragmentManager() != null;
|
||||
|
||||
DialogFragment dialogFragment = null;
|
||||
boolean otherDialogFragment = false;
|
||||
|
||||
DialogFragment dialogFragment = null;
|
||||
if (preference.getKey().equals(getString(R.string.database_name_key))) {
|
||||
dialogFragment = DatabaseNamePreferenceDialogFragmentCompat.newInstance(preference.getKey());
|
||||
}
|
||||
else if (preference.getKey().equals(getString(R.string.database_description_key))) {
|
||||
} else if (preference.getKey().equals(getString(R.string.database_description_key))) {
|
||||
dialogFragment = DatabaseDescriptionPreferenceDialogFragmentCompat.newInstance(preference.getKey());
|
||||
}
|
||||
else if (preference.getKey().equals(getString(R.string.encryption_algorithm_key))) {
|
||||
} else if (preference.getKey().equals(getString(R.string.encryption_algorithm_key))) {
|
||||
dialogFragment = DatabaseEncryptionAlgorithmPreferenceDialogFragmentCompat.newInstance(preference.getKey());
|
||||
}
|
||||
else if (preference.getKey().equals(getString(R.string.key_derivation_function_key))) {
|
||||
} else if (preference.getKey().equals(getString(R.string.key_derivation_function_key))) {
|
||||
DatabaseKeyDerivationPreferenceDialogFragmentCompat keyDerivationDialogFragment = DatabaseKeyDerivationPreferenceDialogFragmentCompat.newInstance(preference.getKey());
|
||||
// Add other prefs to manage
|
||||
if (roundPref != null)
|
||||
@@ -501,24 +516,23 @@ public class NestedSettingsFragment extends PreferenceFragmentCompat
|
||||
if (parallelismPref != null)
|
||||
keyDerivationDialogFragment.setParallelismPreference(parallelismPref);
|
||||
dialogFragment = keyDerivationDialogFragment;
|
||||
}
|
||||
else if (preference.getKey().equals(getString(R.string.transform_rounds_key))) {
|
||||
} else if (preference.getKey().equals(getString(R.string.transform_rounds_key))) {
|
||||
dialogFragment = RoundsPreferenceDialogFragmentCompat.newInstance(preference.getKey());
|
||||
}
|
||||
else if (preference.getKey().equals(getString(R.string.memory_usage_key))) {
|
||||
} else if (preference.getKey().equals(getString(R.string.memory_usage_key))) {
|
||||
dialogFragment = MemoryUsagePreferenceDialogFragmentCompat.newInstance(preference.getKey());
|
||||
}
|
||||
else if (preference.getKey().equals(getString(R.string.parallelism_key))) {
|
||||
} else if (preference.getKey().equals(getString(R.string.parallelism_key))) {
|
||||
dialogFragment = ParallelismPreferenceDialogFragmentCompat.newInstance(preference.getKey());
|
||||
} else {
|
||||
otherDialogFragment = true;
|
||||
}
|
||||
|
||||
if (dialogFragment != null) {
|
||||
if (dialogFragment != null && !databaseReadOnly) {
|
||||
dialogFragment.setTargetFragment(this, 0);
|
||||
dialogFragment.show(getFragmentManager(), null);
|
||||
}
|
||||
|
||||
// Could not be handled here. Try with the super method.
|
||||
else {
|
||||
else if (otherDialogFragment) {
|
||||
super.onDisplayPreferenceDialog(preference);
|
||||
}
|
||||
}
|
||||
@@ -538,6 +552,12 @@ public class NestedSettingsFragment extends PreferenceFragmentCompat
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
ReadOnlyHelper.onSaveInstanceState(outState, databaseReadOnly);
|
||||
super.onSaveInstanceState(outState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
// TODO encapsulate
|
||||
|
||||
@@ -158,6 +158,12 @@ public class PreferencesUtil {
|
||||
context.getResources().getBoolean(R.bool.allow_no_password_default));
|
||||
}
|
||||
|
||||
public static boolean enableReadOnlyDatabase(Context context) {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
return prefs.getBoolean(context.getString(R.string.enable_read_only_key),
|
||||
context.getResources().getBoolean(R.bool.enable_read_only_default));
|
||||
}
|
||||
|
||||
/**
|
||||
* All preference keys associated with education
|
||||
*/
|
||||
@@ -166,6 +172,7 @@ public class PreferencesUtil {
|
||||
R.string.education_select_db_key,
|
||||
R.string.education_open_link_db_key,
|
||||
R.string.education_unlock_key,
|
||||
R.string.education_read_only_key,
|
||||
R.string.education_search_key,
|
||||
R.string.education_new_node_key,
|
||||
R.string.education_sort_key,
|
||||
@@ -245,6 +252,18 @@ public class PreferencesUtil {
|
||||
context.getResources().getBoolean(R.bool.education_unlock_default));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the explanatory view of the database read-only has already been displayed.
|
||||
*
|
||||
* @param context The context to open the SharedPreferences
|
||||
* @return boolean value of education_read_only_key key
|
||||
*/
|
||||
public static boolean isEducationReadOnlyPerformed(Context context) {
|
||||
SharedPreferences prefs = getEducationSharedPreferences(context);
|
||||
return prefs.getBoolean(context.getString(R.string.education_read_only_key),
|
||||
context.getResources().getBoolean(R.bool.education_read_only_default));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the explanatory view of search has already been displayed.
|
||||
*
|
||||
|
||||
@@ -28,6 +28,7 @@ import android.support.v7.widget.Toolbar;
|
||||
import android.view.MenuItem;
|
||||
|
||||
import com.kunzisoft.keepass.R;
|
||||
import com.kunzisoft.keepass.activities.ReadOnlyHelper;
|
||||
import com.kunzisoft.keepass.lock.LockingActivity;
|
||||
|
||||
|
||||
@@ -39,17 +40,18 @@ public class SettingsActivity extends LockingActivity implements MainPreferenceF
|
||||
|
||||
private Toolbar toolbar;
|
||||
|
||||
public static void launch(Activity activity) {
|
||||
Intent i = new Intent(activity, SettingsActivity.class);
|
||||
activity.startActivity(i);
|
||||
public static void launch(Activity activity, boolean readOnly) {
|
||||
Intent intent = new Intent(activity, SettingsActivity.class);
|
||||
ReadOnlyHelper.putReadOnlyInIntent(intent, readOnly);
|
||||
activity.startActivity(intent);
|
||||
}
|
||||
|
||||
public static void launch(Activity activity, boolean checkLock) {
|
||||
public static void launch(Activity activity, boolean readOnly, boolean checkLock) {
|
||||
// To avoid flickering when launch settings in a LockingActivity
|
||||
if (!checkLock)
|
||||
launch(activity);
|
||||
launch(activity, readOnly);
|
||||
else if (LockingActivity.checkTimeIsAllowedOrFinish(activity)) {
|
||||
launch(activity);
|
||||
launch(activity, readOnly);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,7 +116,7 @@ public class SettingsActivity extends LockingActivity implements MainPreferenceF
|
||||
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.fragment_container, NestedSettingsFragment.newInstance(key), TAG_NESTED)
|
||||
.replace(R.id.fragment_container, NestedSettingsFragment.newInstance(key, readOnly), TAG_NESTED)
|
||||
.addToBackStack(TAG_NESTED)
|
||||
.commit();
|
||||
|
||||
|
||||
@@ -88,8 +88,8 @@ public class ProgressTaskDialogFragment extends DialogFragment implements Progre
|
||||
|
||||
@Override
|
||||
public void onDismiss(DialogInterface dialog) {
|
||||
super.onDismiss(dialog);
|
||||
Util.unlockScreenOrientation(getActivity());
|
||||
super.onDismiss(dialog);
|
||||
}
|
||||
|
||||
public static void stop(AppCompatActivity activity) {
|
||||
|
||||
@@ -19,9 +19,14 @@
|
||||
*/
|
||||
package com.kunzisoft.keepass.utils;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
@@ -47,4 +52,68 @@ public class MemUtil {
|
||||
return baos.toByteArray();
|
||||
}
|
||||
|
||||
// For writing to a Parcel
|
||||
public static <K extends Parcelable,V extends Parcelable> void writeParcelableMap(
|
||||
Parcel parcel, int flags, Map<K, V > map) {
|
||||
parcel.writeInt(map.size());
|
||||
for(Map.Entry<K, V> e : map.entrySet()){
|
||||
parcel.writeParcelable(e.getKey(), flags);
|
||||
parcel.writeParcelable(e.getValue(), flags);
|
||||
}
|
||||
}
|
||||
|
||||
// For reading from a Parcel
|
||||
public static <K extends Parcelable,V extends Parcelable> Map<K,V> readParcelableMap(
|
||||
Parcel parcel, Class<K> kClass, Class<V> vClass) {
|
||||
int size = parcel.readInt();
|
||||
Map<K, V> map = new HashMap<K, V>(size);
|
||||
for(int i = 0; i < size; i++){
|
||||
map.put(kClass.cast(parcel.readParcelable(kClass.getClassLoader())),
|
||||
vClass.cast(parcel.readParcelable(vClass.getClassLoader())));
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
// For writing map with string key to a Parcel
|
||||
public static <V extends Parcelable> void writeStringParcelableMap(
|
||||
Parcel parcel, int flags, Map<String, V> map) {
|
||||
parcel.writeInt(map.size());
|
||||
for(Map.Entry<String, V> e : map.entrySet()){
|
||||
parcel.writeString(e.getKey());
|
||||
parcel.writeParcelable(e.getValue(), flags);
|
||||
}
|
||||
}
|
||||
|
||||
// For reading map with string key from a Parcel
|
||||
public static <V extends Parcelable> HashMap<String,V> readStringParcelableMap(
|
||||
Parcel parcel, Class<V> vClass) {
|
||||
int size = parcel.readInt();
|
||||
HashMap<String, V> map = new HashMap<>(size);
|
||||
for(int i = 0; i < size; i++){
|
||||
map.put(parcel.readString(),
|
||||
vClass.cast(parcel.readParcelable(vClass.getClassLoader())));
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
// For writing map with string key and string value to a Parcel
|
||||
public static void writeStringParcelableMap(Parcel dest, Map<String, String> map) {
|
||||
dest.writeInt(map.size());
|
||||
for(Map.Entry<String, String> e : map.entrySet()){
|
||||
dest.writeString(e.getKey());
|
||||
dest.writeString(e.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
// For reading map with string key and string value from a Parcel
|
||||
public static HashMap<String, String> readStringParcelableMap(Parcel in) {
|
||||
int size = in.readInt();
|
||||
HashMap<String, String> map = new HashMap<>(size);
|
||||
for(int i = 0; i < size; i++){
|
||||
map.put(in.readString(),
|
||||
in.readString());
|
||||
}
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,8 @@ import com.kunzisoft.keepass.activities.AboutActivity;
|
||||
import com.kunzisoft.keepass.settings.SettingsActivity;
|
||||
import com.kunzisoft.keepass.stylish.StylishActivity;
|
||||
|
||||
import static com.kunzisoft.keepass.activities.ReadOnlyHelper.READ_ONLY_DEFAULT;
|
||||
|
||||
|
||||
public class MenuUtil {
|
||||
|
||||
@@ -56,20 +58,20 @@ public class MenuUtil {
|
||||
}
|
||||
|
||||
public static boolean onDefaultMenuOptionsItemSelected(StylishActivity activity, MenuItem item) {
|
||||
return onDefaultMenuOptionsItemSelected(activity, item, false);
|
||||
return onDefaultMenuOptionsItemSelected(activity, item, READ_ONLY_DEFAULT, false);
|
||||
}
|
||||
|
||||
/*
|
||||
* @param checkLock Check the time lock before launch settings in LockingActivity
|
||||
*/
|
||||
public static boolean onDefaultMenuOptionsItemSelected(StylishActivity activity, MenuItem item, boolean checkLock) {
|
||||
public static boolean onDefaultMenuOptionsItemSelected(StylishActivity activity, MenuItem item, boolean readOnly, boolean checkLock) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.menu_contribute:
|
||||
return onContributionItemSelected(activity);
|
||||
|
||||
case R.id.menu_app_settings:
|
||||
// To avoid flickering when launch settings in a LockingActivity
|
||||
SettingsActivity.launch(activity, checkLock);
|
||||
SettingsActivity.launch(activity, readOnly, checkLock);
|
||||
return true;
|
||||
|
||||
case R.id.menu_about:
|
||||
|
||||
@@ -86,7 +86,8 @@ public class Util {
|
||||
}
|
||||
|
||||
public static void unlockScreenOrientation(Activity activity) {
|
||||
if (activity != null)
|
||||
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
|
||||
if (activity != null) {
|
||||
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,6 +167,7 @@ public class AddNodeButtonView extends RelativeLayout {
|
||||
this.addEntryEnable = enable;
|
||||
if (enable && addEntryView != null && addEntryView.getVisibility() != VISIBLE)
|
||||
addEntryView.setVisibility(INVISIBLE);
|
||||
disableViewIfNoAddAvailable();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -177,6 +178,19 @@ public class AddNodeButtonView extends RelativeLayout {
|
||||
this.addGroupEnable = enable;
|
||||
if (enable && addGroupView != null && addGroupView.getVisibility() != VISIBLE)
|
||||
addGroupView.setVisibility(INVISIBLE);
|
||||
disableViewIfNoAddAvailable();
|
||||
}
|
||||
|
||||
private void disableViewIfNoAddAvailable() {
|
||||
if (!addEntryEnable || !addGroupEnable) {
|
||||
setVisibility(GONE);
|
||||
} else {
|
||||
setVisibility(VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isVisible() {
|
||||
return getVisibility() == VISIBLE;
|
||||
}
|
||||
|
||||
public void setAddGroupClickListener(OnClickListener onClickListener) {
|
||||
|
||||
19
app/src/main/res/drawable/ic_read_only_white_24dp.xml
Normal file
19
app/src/main/res/drawable/ic_read_only_white_24dp.xml
Normal file
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:width="24dp"
|
||||
android:height="24dp">
|
||||
<group
|
||||
android:translateY="-8">
|
||||
<group
|
||||
android:scaleX="1.777778"
|
||||
android:scaleY="1.777778"
|
||||
android:translateX="-205.4844"
|
||||
android:translateY="-31.99788">
|
||||
<path
|
||||
android:pathData="M125.00684 31.305444l0 -6.644528c0 -0.263013 -0.21159 -0.47461 -0.4746 -0.47461l-6.48633 0c-1.04808 0 -1.89843 0.850344 -1.89843 1.898435l0 6.328127c0 1.048093 0.85035 1.898437 1.89843 1.898437l6.48633 0c0.26301 0 0.4746 -0.2116 0.4746 -0.474611l0 -0.316409c0 -0.148311 -0.0692 -0.282785 -0.176 -0.369792 -0.083 -0.304543 -0.083 -1.172685 0 -1.477229 0.10684 -0.08504 0.176 -0.219501 0.176 -0.36782zm-6.32812 -4.469236c0 -0.06529 0.0534 -0.118652 0.11866 -0.118652l4.19238 0c0.0653 0 0.11866 0.05343 0.11866 0.118652l0 0.39551c0 0.06529 -0.0534 0.118653 -0.11866 0.118653l-4.19238 0c-0.0653 0 -0.11866 -0.05343 -0.11866 -0.118653l0 -0.39551zm0 1.265621c0 -0.06529 0.0534 -0.118653 0.11866 -0.118653l4.19238 0c0.0653 0 0.11866 0.05343 0.11866 0.118653l0 0.395509c0 0.06529 -0.0534 0.118653 -0.11866 0.118653l-4.19238 0c-0.0653 0 -0.11866 -0.05342 -0.11866 -0.118653l0 -0.395509zm5.0111 4.943847l-5.64391 0c-0.35003 0 -0.63282 -0.282781 -0.63282 -0.632808 0 -0.348045 0.28476 -0.632813 0.63282 -0.632813l5.64391 0c-0.0375 0.338162 -0.0375 0.927466 0 1.265621z"
|
||||
android:fillColor="#ffffff" />
|
||||
</group>
|
||||
</group>
|
||||
</vector>
|
||||
25
app/src/main/res/drawable/ic_read_write_white_24dp.xml
Normal file
25
app/src/main/res/drawable/ic_read_write_white_24dp.xml
Normal file
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:width="24dp"
|
||||
android:height="24dp">
|
||||
<group
|
||||
android:translateY="-8">
|
||||
<group
|
||||
android:scaleX="1.777778"
|
||||
android:scaleY="1.777778"
|
||||
android:translateX="-205.4844"
|
||||
android:translateY="-31.99788">
|
||||
<group
|
||||
android:scaleX="0.5625"
|
||||
android:scaleY="0.5625"
|
||||
android:translateX="115.585"
|
||||
android:translateY="22.49881">
|
||||
<path
|
||||
android:pathData="M4.375 3C2.5117466 3 1 4.5117271 1 6.375l0 11.25C1 19.488276 2.5117466 21 4.375 21l11.53125 0C16.373823 21 16.75 20.623825 16.75 20.15625l0 -0.5625c0 -0.263664 -0.122669 -0.503524 -0.3125 -0.658203 -0.147556 -0.54141 -0.147556 -2.08359 0 -2.625 0.189938 -0.151182 0.3125 -0.390619 0.3125 -0.654297l0 -0.669922 -2.378906 2.378906c-0.0089 0.500068 -0.0036 1.014773 0.03711 1.384766l-1.525391 0 -3.0507808 0.667969C9.333649 19.527124 8.7483479 19.391267 8.3632812 19.005859 8.2870146 18.929486 8.2287106 18.840044 8.171875 18.75L4.375 18.75C3.7527244 18.75 3.25 18.24727 3.25 17.625 3.25 17.006253 3.7562267 16.5 4.375 16.5l3.8027344 0L8.6503906 14.349609 12.125 10.875l-6.4140625 0C5.5948486 10.875 5.5 10.780031 5.5 10.664062l0 -0.7031245C5.5 9.8448664 5.5949375 9.75 5.7109375 9.75l7.4531245 0c0.02365 0 0.03921 0.018137 0.06055 0.025391L16.550781 6.4492188 16.75 6.25l0 -2.40625C16.75 3.3761713 16.373823 3 15.90625 3L4.375 3Zm16.015625 1.5898438c-0.30546 0.033979 -0.623906 0.1844704 -0.882813 0.4433593l-1.183593 1.1835938 2.828125 2.828125 1.183594 -1.1835938c0.517848 -0.5180889 0.601704 -1.2752558 0.1875 -1.6894531L21.195312 4.8457031C20.988219 4.6386018 20.696085 4.5558644 20.390625 4.5898438ZM17.320312 7.21875L9.6464844 14.894531 9.015625 17.767578c-0.08448 0.384462 0.1995577 0.670133 0.5839844 0.585938L12.472656 17.724609 20.148438 10.046875 17.320312 7.21875ZM5.7109375 7.5L13.164062 7.5C13.280151 7.5 13.375 7.594987 13.375 7.7109375l0 0.703125C13.375 8.5301336 13.28008 8.625 13.164062 8.625l-7.4531245 0C5.5948486 8.625 5.5 8.5300127 5.5 8.4140625l0 -0.703125C5.5 7.5948664 5.5949375 7.5 5.7109375 7.5Z"
|
||||
android:fillColor="#ffffff" />
|
||||
</group>
|
||||
</group>
|
||||
</group>
|
||||
</vector>
|
||||
27
app/src/main/res/menu/open_file.xml
Normal file
27
app/src/main/res/menu/open_file.xml
Normal file
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<item android:id="@+id/menu_open_file_read_mode_key"
|
||||
android:icon="@drawable/ic_read_write_white_24dp"
|
||||
android:title="@string/menu_open_file_read_and_write"
|
||||
android:orderInCategory="85"
|
||||
app:showAsAction="ifRoom" />
|
||||
</menu>
|
||||
@@ -287,9 +287,9 @@
|
||||
<string name="magic_keyboard_title">Magikeyboard</string>
|
||||
<string name="magic_keyboard_summary">Aktiviert eine eigene Tastatur, die Passwort- und Identitätsfelder ganz einfach ausfüllt.</string>
|
||||
|
||||
<string name="reset_education_screens_title">Hilfe-Anzeige zurücksetzen</string>
|
||||
<string name="reset_education_screens_summary">Elemente hervorheben, um zu lernen wie die Anwendung funktioniert</string>
|
||||
<string name="reset_education_screens_text">Hilfe-Anzeige zurückgesetzt</string>
|
||||
<string name="reset_education_screens_title">Hilfe-Anzeige abschalten</string>
|
||||
<string name="reset_education_screens_summary">Anzeige von Hilfe-Themen abschalten</string>
|
||||
<string name="reset_education_screens_text">Hilfe-Anzeige beendet</string>
|
||||
<string name="education_create_database_title">Ihre Datenbankdatei erstellen</string>
|
||||
<string name="education_create_database_summary">Sie kennen KeePass DX noch nicht, erstellen Sie Ihre erste Passwortmanager-Datei.</string>
|
||||
<string name="education_select_database_title">Existierende Datenbank öffnen</string>
|
||||
@@ -341,4 +341,28 @@
|
||||
|
||||
<string name="icon_pack_choose_title">Icon-Paket auswählen</string>
|
||||
<string name="icon_pack_choose_summary">Das Symbolpaket der Anwendung ändern</string>
|
||||
</resources>
|
||||
<string name="error_move_folder_in_itself">Eine Gruppe kann nicht in sich selbst verschoben werden.</string>
|
||||
<string name="menu_copy">Kopieren</string>
|
||||
<string name="menu_move">Verschieben</string>
|
||||
<string name="menu_paste">Einfügen</string>
|
||||
<string name="menu_cancel">Abbrechen</string>
|
||||
<string name="clipboard_warning">Einige Geräte sind nicht in der Lage, die Zwischenablage automatisch zu leeren. Ist die Löschung durch den Gerätemanager nicht möglich, müssen die kopierten Elemente manuell aus der Zwischenablage gelöscht werden.</string>
|
||||
<string name="allow_copy_password_warning">WARNUNG : Alle Anwendungen teilen sich die Zwischenablage. Wenn sensible Daten kopiert werden, kann andere Software darauf zugreifen.</string>
|
||||
<string name="magic_keyboard_preference_title">Magikeyboard-Einstellungen</string>
|
||||
<string name="magic_keyboard_configure_title">Wie funktioniert die Tastaturkonfiguration zum sicheren Ausfüllen von Formularen?</string>
|
||||
<string name="magic_keyboard_activate_setting_text">Aktivieren Sie das Magikeyboard in den Geräteeinstellungen.</string>
|
||||
<string name="magic_keyboard_activate_setting_path_1_text">Einstellungen -> Sprachen & Eingabe -> Aktuelle Tastatur -> TASTATUR ÄNDERN</string>
|
||||
<string name="magic_keyboard_activate_setting_path_2_text">oder (Einstellungen -> System -> Sprachen & Eingabe -> Bildschirmtastatur -> Tastaturen verwalten)</string>
|
||||
<string name="keyboards_choose_magikeyboard_text">Wählen Sie das Magikeyboard aus, wenn Sie ein Formular ausfüllen müssen.</string>
|
||||
<string name="keyboards_swicth_magikeyboard_text">Sie können leicht von Ihrer Haupttastatur auf Magikeyboard umschalten, entweder mit der Sprachentaste Ihrer Tastatur, durch einen langen Druck auf die Leertaste oder, wenn das nicht zur Verfügung steht, mit :</string>
|
||||
<string name="keyboard_select_entry_text">Wählen Sie den Eintrag mit dem Schlüssel aus.</string>
|
||||
<string name="keyboard_fill_field_text">Füllen Sie die Felder mit den Elementen des Eintrags aus.</string>
|
||||
<string name="keyboard_lock_database_text">Sperren Sie die Datenbank.</string>
|
||||
<string name="keyboard_back_main_keyboard_text">Kehren Sie zur Haupttastatur zurück.</string>
|
||||
|
||||
<string name="allow_no_password_title">Kein Passwort zulassen</string>
|
||||
<string name="allow_no_password_summary">Öffnen-Taste aktivieren, wenn keine Passwort-Identifikation festgelegt ist.</string>
|
||||
|
||||
<string name="enable_education_screens_title">Hilfe-Anzeige</string>
|
||||
<string name="enable_education_screens_summary">Bedienelemente hervorheben, um die Funktionsweise der Anwendung zu lernen</string>
|
||||
</resources>
|
||||
|
||||
@@ -350,4 +350,24 @@
|
||||
<string name="icon_pack_choose_title">Choisir un pack d\'icones</string>
|
||||
<string name="icon_pack_choose_summary">Changer le pack d\'icones de l\'application</string>
|
||||
|
||||
</resources>
|
||||
<string name="error_move_folder_in_itself">Impossible de déplacer un groupe en lui-même.</string>
|
||||
<string name="menu_copy">Copier</string>
|
||||
<string name="menu_move">Déplacer</string>
|
||||
<string name="menu_paste">Coller</string>
|
||||
<string name="menu_cancel">Annuler</string>
|
||||
<string name="magic_keyboard_preference_title">Paramètres du Magikeyboard</string>
|
||||
<string name="magic_keyboard_configure_title">Comment configurer le clavier pour le remplissage sécurisé de formulaire ?</string>
|
||||
<string name="magic_keyboard_activate_setting_text">Activer le Magikeyboard dans les paramètres de l\'appareil.</string>
|
||||
<string name="magic_keyboard_activate_setting_path_1_text">Paramètres -> Langue et saisie -> Clavier actuel -> CHOISIR LES CLAVIERS</string>
|
||||
<string name="magic_keyboard_activate_setting_path_2_text">ou (Paramètres -> Système -> Langues et saisie -> Clavier virtuel -> Gérer les claviers)</string>
|
||||
<string name="keyboards_choose_magikeyboard_text">Choisir le Magikeyboard lorsque vous avez besoin de remplir un formulaire.</string>
|
||||
<string name="keyboards_swicth_magikeyboard_text">Vous pouvez facilement passer de votre clavier principal à Magikeyboard avec le bouton langage de votre clavier, un appui long sur la barre d\'espace de votre clavier, ou, si ce n\'est pas disponible, avec :</string>
|
||||
<string name="keyboard_select_entry_text">Sélectionnez votre entrée avec la clé.</string>
|
||||
<string name="keyboard_fill_field_text">Remplissez vos champs avec les éléments de l\'entrée.</string>
|
||||
<string name="keyboard_lock_database_text">Verrouiller la base de données.</string>
|
||||
<string name="keyboard_back_main_keyboard_text">Retourner sur votre clavier principal.</string>
|
||||
|
||||
<string name="allow_no_password_title">Autoriser aucun mot de passe</string>
|
||||
<string name="allow_no_password_summary">Activer le bouton d\'ouverture si aucune identification de mot de passe n\'est sélectionnée.</string>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<!--
|
||||
Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
|
||||
|
||||
@@ -32,13 +32,13 @@
|
||||
<string name="brackets">括号</string>
|
||||
<string name="browser_intall_text"> 浏览文件需要安装Open Intents File Manager软件,点下面安装。由于一些文件管理软件的差异,在你第一次浏览时可能无法正常工作。</string>
|
||||
<string name="cancel">取消</string>
|
||||
<string name="clipboard_cleared">剪贴板已清除。</string>
|
||||
<string name="clipboard_timeout">剪贴板超时。</string>
|
||||
<string name="clipboard_cleared">剪贴板已清空</string>
|
||||
<string name="clipboard_timeout">剪贴板超时</string>
|
||||
<string name="clipboard_timeout_summary">复制用户名或密码到剪贴板后清除的时间</string>
|
||||
<string name="select_to_copy">复制%1$s到剪贴板</string>
|
||||
<string name="creating_db_key">创建数据库密钥…</string>
|
||||
<string name="creating_db_key">创建数据库密钥…</string>
|
||||
<string name="database">数据库</string>
|
||||
<string name="decrypting_db">解密数据库内容中…</string>
|
||||
<string name="decrypting_db">解密数据库内容中…</string>
|
||||
<string name="default_checkbox">使用这做为我的默认数据库</string>
|
||||
<string name="digits">数字</string>
|
||||
<string name="disclaimer_formal">KeePass DX \u00A9 %1$d Kunzisoft;软件不带有绝对担保;是自由软件,您可在遵循GPL 3或者更高版本的情况下重新发布。中文简繁体翻译:wangkf@gmail.com</string>
|
||||
@@ -91,7 +91,7 @@
|
||||
<string name="length">长度</string>
|
||||
<string name="list_size_title">群列表尺寸</string>
|
||||
<string name="list_size_summary">群列表中的文本尺寸</string>
|
||||
<string name="loading_database">加载数据库中…</string>
|
||||
<string name="loading_database">加载数据库中…</string>
|
||||
<string name="lowercase">小写</string>
|
||||
<string name="maskpass_title">密码掩膜</string>
|
||||
<string name="maskpass_summary">默认隐藏密码</string>
|
||||
@@ -112,8 +112,8 @@
|
||||
<string name="no_results">没有搜索结果</string>
|
||||
<string name="no_url_handler">没有这个链接的处理程序。</string>
|
||||
<string name="open_recent">打开最近数据库:</string>
|
||||
<string name="progress_create">创建新数据库中…</string>
|
||||
<string name="progress_title">工作中…</string>
|
||||
<string name="progress_create">创建新数据库中…</string>
|
||||
<string name="progress_title">工作中…</string>
|
||||
<string name="remember_keyfile_summary">记住密钥文件的位置</string>
|
||||
<string name="remember_keyfile_title">保存密钥文件</string>
|
||||
<string name="remove_from_filelist">移除</string>
|
||||
@@ -122,7 +122,7 @@
|
||||
<string name="rounds">加密次数</string>
|
||||
<string name="rounds_explanation">更高级的加密次数对暴力攻击能提供额外保护,但也会增加加载和保存的时间。</string>
|
||||
<string name="rounds_hint">次数</string>
|
||||
<string name="saving_database">正在保存数据库…</string>
|
||||
<string name="saving_database">正在保存数据库…</string>
|
||||
<string name="space">空格</string>
|
||||
<string name="search_label">搜索</string>
|
||||
<string name="sort_db">数据库的排序顺序</string>
|
||||
@@ -153,4 +153,22 @@
|
||||
<item>中</item>
|
||||
<item>大</item>
|
||||
</string-array>
|
||||
<string name="add_string">添加字符串</string>
|
||||
<string name="encryption">加密</string>
|
||||
<string name="beta_dontask">不再显示</string>
|
||||
<string name="extended_ASCII">拓展版ASCⅡ码</string>
|
||||
<string name="allow">允许</string>
|
||||
<string name="clipboard_error_title">剪切板错误</string>
|
||||
<string name="clipboard_error">某些三星Android手机由于剪切板有bug导致无法从应用复制。更多信息参见:</string>
|
||||
<string name="clipboard_error_clear">清空剪切板失败</string>
|
||||
<string name="clipboard_swipe_clean">滑动以清空剪切板</string>
|
||||
<string name="encryption_chacha20">ChaCha20</string>
|
||||
|
||||
<string name="kdf_AES">AES-KDF</string>
|
||||
<string name="kdf_Argon2">Argon2</string>
|
||||
|
||||
<string name="style_choose_title">选择主题</string>
|
||||
<string name="icon_pack_choose_title">选择图标包</string>
|
||||
<string name="icon_pack_choose_summary">切换应用图标包</string>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -88,6 +88,7 @@
|
||||
<string name="education_select_db_key" translatable="false">education_select_db_key</string>
|
||||
<string name="education_open_link_db_key" translatable="false">education_open_link_db_key</string>
|
||||
<string name="education_unlock_key" translatable="false">education_unlock_key</string>
|
||||
<string name="education_read_only_key" translatable="false">education_read_only_key</string>
|
||||
<string name="education_search_key" translatable="false">education_search_key</string>
|
||||
<string name="education_new_node_key" translatable="false">education_new_node_key</string>
|
||||
<string name="education_sort_key" translatable="false">education_sort_key</string>
|
||||
@@ -102,6 +103,7 @@
|
||||
<string name="magic_keyboard_key" translatable="false">magic_keyboard_key</string>
|
||||
<string name="magic_keyboard_preference_key" translatable="false">magic_keyboard_preference_key</string>
|
||||
<string name="allow_no_password_key" translatable="false">allow_no_password_key</string>
|
||||
<string name="enable_read_only_key" translatable="false">enable_read_only_key</string>
|
||||
|
||||
<bool name="maskpass_default" translatable="false">true</bool>
|
||||
<bool name="keyfile_default" translatable="false">true</bool>
|
||||
@@ -124,6 +126,7 @@
|
||||
<bool name="education_select_db_default" translatable="false">false</bool>
|
||||
<bool name="education_open_link_db_default" translatable="false">false</bool>
|
||||
<bool name="education_unlock_default" translatable="false">false</bool>
|
||||
<bool name="education_read_only_default" translatable="false">false</bool>
|
||||
<bool name="education_search_default" translatable="false">false</bool>
|
||||
<bool name="education_new_node_default" translatable="false">false</bool>
|
||||
<bool name="education_sort_default" translatable="false">false</bool>
|
||||
@@ -135,6 +138,7 @@
|
||||
<bool name="education_screen_reclicked_default" translatable="false">false</bool>
|
||||
<bool name="magic_keyboard_default" translatable="false">false</bool>
|
||||
<bool name="allow_no_password_default" translatable="false">true</bool>
|
||||
<bool name="enable_read_only_default" translatable="false">false</bool>
|
||||
|
||||
<string name="app_timeout_default" translatable="false">300000</string>
|
||||
<string name="clipboard_timeout_default" translatable="false">60000</string>
|
||||
|
||||
@@ -134,6 +134,8 @@
|
||||
<string name="menu_showpass">Show pass</string>
|
||||
<string name="menu_fingerprint_remove_key">Remove the fingerprint key</string>
|
||||
<string name="menu_url">Go to URL</string>
|
||||
<string name="menu_file_selection_read_only">Read only</string>
|
||||
<string name="menu_open_file_read_and_write">Read and write</string>
|
||||
<string name="minus">Minus</string>
|
||||
<string name="never">Never</string>
|
||||
<string name="no_results">No search results</string>
|
||||
@@ -264,7 +266,7 @@
|
||||
<string name="other">Other</string>
|
||||
|
||||
<string name="keyboard">Keyboard</string>
|
||||
<string name="magic_keyboard_title">Magikeyboayd</string>
|
||||
<string name="magic_keyboard_title">Magikeyboard</string>
|
||||
<string name="magic_keyboard_summary">Activate a custom keyboard that populates your passwords and all your identity fields easily.</string>
|
||||
<string name="magic_keyboard_preference_title">Magikeyboard settings</string>
|
||||
<string name="magic_keyboard_configure_title">How to configure the keyboard for secure form filling?</string>
|
||||
@@ -280,6 +282,8 @@
|
||||
|
||||
<string name="allow_no_password_title">Allow no password</string>
|
||||
<string name="allow_no_password_summary">Enable the open button if no password identification is selected.</string>
|
||||
<string name="enable_read_only_title">Read only</string>
|
||||
<string name="enable_read_only_summary">By default, open a database in read-only mode.</string>
|
||||
|
||||
<string name="enable_education_screens_title">Education screens</string>
|
||||
<string name="enable_education_screens_summary">Highlight the elements to learn how the application works</string>
|
||||
@@ -306,6 +310,8 @@
|
||||
<string name="education_entry_new_field_summary">You want to register a basic non-supplied field, simply fill in a new one that you can also protect visually.</string>
|
||||
<string name="education_unlock_title">Unlock your database</string>
|
||||
<string name="education_unlock_summary">Enter a password and/or a key file to unlock your database.\n\nRemember to save a copy of your file in a safe place after each modification.</string>
|
||||
<string name="education_read_only_title">Enable read-only</string>
|
||||
<string name="education_read_only_summary">Change the opening mode for the session.\n\nIn read-only mode, you prevent unintended changes to the database.\n\nIn write mode, you can add, delete, or modify all the elements as you want.</string>
|
||||
<string name="education_field_copy_title">Copy a field</string>
|
||||
<string name="education_field_copy_summary">Copy a field easily to paste it where you want\n\nYou can use several forms filling methods. Use the one you prefer!</string>
|
||||
<string name="education_lock_title">Lock the database</string>
|
||||
|
||||
@@ -28,6 +28,11 @@
|
||||
android:defaultValue="@bool/allow_no_password_default"
|
||||
android:title="@string/allow_no_password_title"
|
||||
android:key="@string/allow_no_password_key"/>
|
||||
<SwitchPreference
|
||||
android:summary="@string/enable_read_only_summary"
|
||||
android:defaultValue="@bool/enable_read_only_default"
|
||||
android:title="@string/enable_read_only_title"
|
||||
android:key="@string/enable_read_only_key"/>
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
|
||||
92
art/ic_read_only.svg
Normal file
92
art/ic_read_only.svg
Normal file
@@ -0,0 +1,92 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="24"
|
||||
height="24"
|
||||
id="svg4830"
|
||||
version="1.1"
|
||||
inkscape:version="0.91 r13725"
|
||||
inkscape:export-filename="/home/joker/Project/Scratcheck/TestExport.png"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90"
|
||||
sodipodi:docname="ic_read_only.svg">
|
||||
<defs
|
||||
id="defs4832" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#acacac"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="8"
|
||||
inkscape:cx="-37.548191"
|
||||
inkscape:cy="-10.060761"
|
||||
inkscape:current-layer="g4770"
|
||||
showgrid="true"
|
||||
inkscape:grid-bbox="true"
|
||||
inkscape:document-units="px"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1023"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="27"
|
||||
inkscape:window-maximized="1">
|
||||
<sodipodi:guide
|
||||
position="0.99999471,22.999999"
|
||||
orientation="22,0"
|
||||
id="guide2987" />
|
||||
<sodipodi:guide
|
||||
position="0.99999471,0.99999888"
|
||||
orientation="0,22"
|
||||
id="guide2989" />
|
||||
<sodipodi:guide
|
||||
position="22.999995,0.99999888"
|
||||
orientation="-22,0"
|
||||
id="guide2991" />
|
||||
<sodipodi:guide
|
||||
position="22.999995,22.999999"
|
||||
orientation="0,-22"
|
||||
id="guide2993" />
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid2989" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata4835">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
transform="translate(0,-8)">
|
||||
<g
|
||||
id="g4770"
|
||||
transform="matrix(1.7777778,0,0,1.7777778,-205.48441,-31.997877)">
|
||||
<g
|
||||
id="Layer_1"
|
||||
transform="matrix(-0.00397893,0,0,0.00397893,125.58386,23.674135)" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#ffffff;fill-opacity:1"
|
||||
d="m 125.00684,31.305444 0,-6.644528 c 0,-0.263013 -0.21159,-0.47461 -0.4746,-0.47461 l -6.48633,0 c -1.04808,0 -1.89843,0.850344 -1.89843,1.898435 l 0,6.328127 c 0,1.048093 0.85035,1.898437 1.89843,1.898437 l 6.48633,0 c 0.26301,0 0.4746,-0.2116 0.4746,-0.474611 l 0,-0.316409 c 0,-0.148311 -0.0692,-0.282785 -0.176,-0.369792 -0.083,-0.304543 -0.083,-1.172685 0,-1.477229 0.10684,-0.08504 0.176,-0.219501 0.176,-0.36782 z m -6.32812,-4.469236 c 0,-0.06529 0.0534,-0.118652 0.11866,-0.118652 l 4.19238,0 c 0.0653,0 0.11866,0.05343 0.11866,0.118652 l 0,0.39551 c 0,0.06529 -0.0534,0.118653 -0.11866,0.118653 l -4.19238,0 c -0.0653,0 -0.11866,-0.05343 -0.11866,-0.118653 l 0,-0.39551 z m 0,1.265621 c 0,-0.06529 0.0534,-0.118653 0.11866,-0.118653 l 4.19238,0 c 0.0653,0 0.11866,0.05343 0.11866,0.118653 l 0,0.395509 c 0,0.06529 -0.0534,0.118653 -0.11866,0.118653 l -4.19238,0 c -0.0653,0 -0.11866,-0.05342 -0.11866,-0.118653 l 0,-0.395509 z m 5.0111,4.943847 -5.64391,0 c -0.35003,0 -0.63282,-0.282781 -0.63282,-0.632808 0,-0.348045 0.28476,-0.632813 0.63282,-0.632813 l 5.64391,0 c -0.0375,0.338162 -0.0375,0.927466 0,1.265621 z"
|
||||
id="path4" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.7 KiB |
92
art/ic_read_write.svg
Normal file
92
art/ic_read_write.svg
Normal file
@@ -0,0 +1,92 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="24"
|
||||
height="24"
|
||||
id="svg4830"
|
||||
version="1.1"
|
||||
inkscape:version="0.91 r13725"
|
||||
inkscape:export-filename="/home/joker/Project/Scratcheck/TestExport.png"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90"
|
||||
sodipodi:docname="ic_read_write.svg">
|
||||
<defs
|
||||
id="defs4832" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#acacac"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="11.313708"
|
||||
inkscape:cx="-12.80892"
|
||||
inkscape:cy="-4.0293631"
|
||||
inkscape:current-layer="g4770"
|
||||
showgrid="true"
|
||||
inkscape:grid-bbox="true"
|
||||
inkscape:document-units="px"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1023"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="27"
|
||||
inkscape:window-maximized="1">
|
||||
<sodipodi:guide
|
||||
position="0.99999471,22.999999"
|
||||
orientation="22,0"
|
||||
id="guide2987" />
|
||||
<sodipodi:guide
|
||||
position="0.99999471,0.99999888"
|
||||
orientation="0,22"
|
||||
id="guide2989" />
|
||||
<sodipodi:guide
|
||||
position="22.999995,0.99999888"
|
||||
orientation="-22,0"
|
||||
id="guide2991" />
|
||||
<sodipodi:guide
|
||||
position="39,23"
|
||||
orientation="0,-22"
|
||||
id="guide2993" />
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid2989" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata4835">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
transform="translate(0,-8)">
|
||||
<g
|
||||
id="g4770"
|
||||
transform="matrix(1.7777778,0,0,1.7777778,-205.48441,-31.997877)">
|
||||
<g
|
||||
id="Layer_1"
|
||||
transform="matrix(-0.00397893,0,0,0.00397893,125.58386,23.674135)" />
|
||||
<path
|
||||
style="fill:#ffffff;fill-opacity:1"
|
||||
d="M 4.375 3 C 2.5117466 3 1 4.5117271 1 6.375 L 1 17.625 C 1 19.488276 2.5117466 21 4.375 21 L 15.90625 21 C 16.373823 21 16.75 20.623825 16.75 20.15625 L 16.75 19.59375 C 16.75 19.330086 16.627331 19.090226 16.4375 18.935547 C 16.289944 18.394137 16.289944 16.851957 16.4375 16.310547 C 16.627438 16.159365 16.75 15.919928 16.75 15.65625 L 16.75 14.986328 L 14.371094 17.365234 C 14.362205 17.865302 14.367492 18.380007 14.408203 18.75 L 12.882812 18.75 L 9.8320312 19.417969 C 9.333649 19.527124 8.7483479 19.391267 8.3632812 19.005859 C 8.2870146 18.929486 8.2287106 18.840044 8.171875 18.75 L 4.375 18.75 C 3.7527244 18.75 3.25 18.24727 3.25 17.625 C 3.25 17.006253 3.7562267 16.5 4.375 16.5 L 8.1777344 16.5 L 8.6503906 14.349609 L 12.125 10.875 L 5.7109375 10.875 C 5.5948486 10.875 5.5 10.780031 5.5 10.664062 L 5.5 9.9609375 C 5.5 9.8448664 5.5949375 9.75 5.7109375 9.75 L 13.164062 9.75 C 13.187707 9.75 13.203276 9.7681373 13.224609 9.7753906 L 16.550781 6.4492188 L 16.75 6.25 L 16.75 3.84375 C 16.75 3.3761713 16.373823 3 15.90625 3 L 4.375 3 z M 20.390625 4.5898438 C 20.085165 4.6238231 19.766719 4.7743142 19.507812 5.0332031 L 18.324219 6.2167969 L 21.152344 9.0449219 L 22.335938 7.8613281 C 22.853786 7.3432392 22.937642 6.5860723 22.523438 6.171875 L 21.195312 4.8457031 C 20.988219 4.6386018 20.696085 4.5558644 20.390625 4.5898438 z M 17.320312 7.21875 L 9.6464844 14.894531 L 9.015625 17.767578 C 8.931145 18.15204 9.2151827 18.437711 9.5996094 18.353516 L 12.472656 17.724609 L 20.148438 10.046875 L 17.320312 7.21875 z M 5.7109375 7.5 L 13.164062 7.5 C 13.280151 7.5 13.375 7.5949873 13.375 7.7109375 L 13.375 8.4140625 C 13.375 8.5301336 13.28008 8.625 13.164062 8.625 L 5.7109375 8.625 C 5.5948486 8.625 5.5 8.5300127 5.5 8.4140625 L 5.5 7.7109375 C 5.5 7.5948664 5.5949375 7.5 5.7109375 7.5 z "
|
||||
transform="matrix(0.56249999,0,0,0.56249999,115.58498,22.498806)"
|
||||
id="path4" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.4 KiB |
@@ -3,5 +3,5 @@
|
||||
* New navigation in a single screen / new animations between activities
|
||||
* New icons for the material pack
|
||||
* New adaptive launcher icon
|
||||
* Added a setting to disable the open button when no password is identified / the education screens / the copy of protected custom fields
|
||||
* Fix the fingerprint recognition (WARNING : The keystore is reinit, you must delete the old keys)
|
||||
* Added a setting to disable the open button / the education screens / the copy of protected custom fields
|
||||
* Fix the fingerprint recognition
|
||||
7
fastlane/metadata/android/en-US/changelogs/13.txt
Normal file
7
fastlane/metadata/android/en-US/changelogs/13.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
* Added the Magikeyboard to fill the forms
|
||||
* Added move and copy for groups and entries
|
||||
* New navigation in a single screen / new animations between activities
|
||||
* New icons for the material pack
|
||||
* New adaptive launcher icon
|
||||
* Added a setting to disable the open button / the education screens / the copy of protected custom fields
|
||||
* Fix the fingerprint recognition / crash in beta 12
|
||||
7
fastlane/metadata/android/en-US/changelogs/14.txt
Normal file
7
fastlane/metadata/android/en-US/changelogs/14.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
* Added the Magikeyboard to fill the forms
|
||||
* Added move and copy for groups and entries
|
||||
* New navigation in a single screen / new animations between activities
|
||||
* New icons for the material pack
|
||||
* New adaptive launcher icon
|
||||
* Added a setting to disable the open button / the education screens / the copy of protected custom fields
|
||||
* Fix the fingerprint recognition / crash / search / parcelables
|
||||
5
fastlane/metadata/android/en-US/changelogs/15.txt
Normal file
5
fastlane/metadata/android/en-US/changelogs/15.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
* Read only mode
|
||||
* Best group recovery for the navigation fragment
|
||||
* Fix copies in notifications
|
||||
* Fix orientation
|
||||
* Added translations
|
||||
@@ -3,5 +3,5 @@
|
||||
* Nouvelle navigation dans un seul écran / nouvelles animations entre activités
|
||||
* Nouveaux icones pour le pack material
|
||||
* Nouvel icone de lancement adaptatif
|
||||
* Ajout d'un paramètre pour désactiver le bouton d'ouverture quand aucun mot de passe n'est identifié / les écrans d'éducation / la copie des champs customisés protégés
|
||||
* Correction de la reconnaissance des empreintes digitales (ATTENTION: le keystore est réinitialisé, vous devez supprimer les anciennes clés)
|
||||
* Ajout d'un paramètre pour désactiver le bouton d'ouverture / les écrans d'éducation / la copie des champs customisés protégés
|
||||
* Correction de la reconnaissance des empreintes digitales
|
||||
7
fastlane/metadata/android/fr-FR/changelogs/13.txt
Normal file
7
fastlane/metadata/android/fr-FR/changelogs/13.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
* Ajout du Magikeyboard pour remplir les formulaires
|
||||
* Déplacer et copier ajoutés pour les groupes et les entrées
|
||||
* Nouvelle navigation dans un seul écran / nouvelles animations entre activités
|
||||
* Nouveaux icones pour le pack material
|
||||
* Nouvel icone de lancement adaptatif
|
||||
* Ajout d'un paramètre pour désactiver le bouton d'ouverture / les écrans d'éducation / la copie des champs customisés protégés
|
||||
* Correction de la reconnaissance des empreintes digitales / crash de la beta 12
|
||||
7
fastlane/metadata/android/fr-FR/changelogs/14.txt
Normal file
7
fastlane/metadata/android/fr-FR/changelogs/14.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
* Ajout du Magikeyboard pour remplir les formulaires
|
||||
* Déplacer et copier ajoutés pour les groupes et les entrées
|
||||
* Nouvelle navigation dans un seul écran / nouvelles animations entre activités
|
||||
* Nouveaux icones pour le pack material
|
||||
* Nouvel icone de lancement adaptatif
|
||||
* Ajout d'un paramètre pour désactiver le bouton d'ouverture / les écrans d'éducation / la copie des champs customisés protégés
|
||||
* Correction de la reconnaissance des empreintes digitales / crash / recherche / parcelables
|
||||
5
fastlane/metadata/android/fr-FR/changelogs/15.txt
Normal file
5
fastlane/metadata/android/fr-FR/changelogs/15.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
* Mode lecture seule
|
||||
* Meilleur récupération des groupes pour le fragment de navigation
|
||||
* Correction des copies dans les notifications
|
||||
* Correction de l'orientation
|
||||
* Ajout des traductions
|
||||
@@ -98,10 +98,14 @@ public class MagikIME extends InputMethodService
|
||||
}
|
||||
|
||||
private void assignKeyboardView() {
|
||||
if (entryKey != null) {
|
||||
keyboardView.setKeyboard(keyboard_entry);
|
||||
} else {
|
||||
keyboardView.setKeyboard(keyboard);
|
||||
if (keyboardView != null) {
|
||||
if (entryKey != null) {
|
||||
if (keyboard_entry != null)
|
||||
keyboardView.setKeyboard(keyboard_entry);
|
||||
} else {
|
||||
if (keyboard != null)
|
||||
keyboardView.setKeyboard(keyboard);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user