mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
Refactor Autofill and Keyboard selection
This commit is contained in:
@@ -126,10 +126,10 @@
|
|||||||
android:configChanges="orientation|keyboardHidden"
|
android:configChanges="orientation|keyboardHidden"
|
||||||
android:windowSoftInputMode="stateHidden" />
|
android:windowSoftInputMode="stateHidden" />
|
||||||
<activity android:name="com.kunzisoft.keepass.settings.SettingsActivity" />
|
<activity android:name="com.kunzisoft.keepass.settings.SettingsActivity" />
|
||||||
<activity android:name="com.kunzisoft.keepass.autofill.AutoFillAuthActivity"
|
<activity android:name="com.kunzisoft.keepass.autofill.AutoFillLauncherActivity"
|
||||||
android:configChanges="orientation|keyboardHidden" />
|
android:configChanges="orientation|keyboardHidden" />
|
||||||
<activity android:name="com.kunzisoft.keepass.settings.SettingsAutofillActivity" />
|
<activity android:name="com.kunzisoft.keepass.settings.SettingsAutofillActivity" />
|
||||||
<activity android:name="com.kunzisoft.keepass.selection.KeyboardEntryRetrieverActivity"
|
<activity android:name="com.kunzisoft.keepass.magikeyboard.KeyboardLauncherActivity"
|
||||||
android:label="@string/keyboard_name">
|
android:label="@string/keyboard_name">
|
||||||
</activity>
|
</activity>
|
||||||
<activity android:name="com.kunzisoft.keepass.settings.MagikIMESettings"
|
<activity android:name="com.kunzisoft.keepass.settings.MagikIMESettings"
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ public class EntryActivity extends LockingHideActivity {
|
|||||||
private int iconColor;
|
private int iconColor;
|
||||||
|
|
||||||
public static void launch(Activity activity, PwEntry pw, boolean readOnly) {
|
public static void launch(Activity activity, PwEntry pw, boolean readOnly) {
|
||||||
if (TimeoutHelper.INSTANCE.checkTime(activity)) {
|
if (TimeoutHelper.INSTANCE.checkTimeAndLockIfTimeout(activity)) {
|
||||||
Intent intent = new Intent(activity, EntryActivity.class);
|
Intent intent = new Intent(activity, EntryActivity.class);
|
||||||
intent.putExtra(KEY_ENTRY, Types.UUIDtoBytes(pw.getUUID()));
|
intent.putExtra(KEY_ENTRY, Types.UUIDtoBytes(pw.getUUID()));
|
||||||
ReadOnlyHelper.putReadOnlyInIntent(intent, readOnly);
|
ReadOnlyHelper.putReadOnlyInIntent(intent, readOnly);
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ public class EntryEditActivity extends LockingHideActivity
|
|||||||
* @param pwEntry Entry to update
|
* @param pwEntry Entry to update
|
||||||
*/
|
*/
|
||||||
public static void launch(Activity activity, PwEntry pwEntry) {
|
public static void launch(Activity activity, PwEntry pwEntry) {
|
||||||
if (TimeoutHelper.INSTANCE.checkTime(activity)) {
|
if (TimeoutHelper.INSTANCE.checkTimeAndLockIfTimeout(activity)) {
|
||||||
Intent intent = new Intent(activity, EntryEditActivity.class);
|
Intent intent = new Intent(activity, EntryEditActivity.class);
|
||||||
intent.putExtra(KEY_ENTRY, Types.UUIDtoBytes(pwEntry.getUUID()));
|
intent.putExtra(KEY_ENTRY, Types.UUIDtoBytes(pwEntry.getUUID()));
|
||||||
activity.startActivityForResult(intent, ADD_OR_UPDATE_ENTRY_REQUEST_CODE);
|
activity.startActivityForResult(intent, ADD_OR_UPDATE_ENTRY_REQUEST_CODE);
|
||||||
@@ -131,7 +131,7 @@ public class EntryEditActivity extends LockingHideActivity
|
|||||||
* @param pwGroup Group who will contains new entry
|
* @param pwGroup Group who will contains new entry
|
||||||
*/
|
*/
|
||||||
public static void launch(Activity activity, PwGroup pwGroup) {
|
public static void launch(Activity activity, PwGroup pwGroup) {
|
||||||
if (TimeoutHelper.INSTANCE.checkTime(activity)) {
|
if (TimeoutHelper.INSTANCE.checkTimeAndLockIfTimeout(activity)) {
|
||||||
Intent intent = new Intent(activity, EntryEditActivity.class);
|
Intent intent = new Intent(activity, EntryEditActivity.class);
|
||||||
intent.putExtra(KEY_PARENT, pwGroup.getId());
|
intent.putExtra(KEY_PARENT, pwGroup.getId());
|
||||||
activity.startActivityForResult(intent, ADD_OR_UPDATE_ENTRY_REQUEST_CODE);
|
activity.startActivityForResult(intent, ADD_OR_UPDATE_ENTRY_REQUEST_CODE);
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ import android.os.Build;
|
|||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.annotation.RequiresApi;
|
import android.support.annotation.RequiresApi;
|
||||||
import android.support.v4.app.Fragment;
|
import android.support.v4.app.Fragment;
|
||||||
@@ -81,6 +82,9 @@ import com.kunzisoft.keepass.dialogs.GroupEditDialogFragment;
|
|||||||
import com.kunzisoft.keepass.dialogs.IconPickerDialogFragment;
|
import com.kunzisoft.keepass.dialogs.IconPickerDialogFragment;
|
||||||
import com.kunzisoft.keepass.dialogs.ReadOnlyDialog;
|
import com.kunzisoft.keepass.dialogs.ReadOnlyDialog;
|
||||||
import com.kunzisoft.keepass.dialogs.SortDialogFragment;
|
import com.kunzisoft.keepass.dialogs.SortDialogFragment;
|
||||||
|
import com.kunzisoft.keepass.magikeyboard.KeyboardEntryNotificationService;
|
||||||
|
import com.kunzisoft.keepass.magikeyboard.KeyboardHelper;
|
||||||
|
import com.kunzisoft.keepass.magikeyboard.MagikIME;
|
||||||
import com.kunzisoft.keepass.password.AssignPasswordHelper;
|
import com.kunzisoft.keepass.password.AssignPasswordHelper;
|
||||||
import com.kunzisoft.keepass.selection.EntrySelectionHelper;
|
import com.kunzisoft.keepass.selection.EntrySelectionHelper;
|
||||||
import com.kunzisoft.keepass.settings.PreferencesUtil;
|
import com.kunzisoft.keepass.settings.PreferencesUtil;
|
||||||
@@ -132,16 +136,13 @@ public class GroupActivity extends LockingActivity
|
|||||||
private PwNode nodeToCopy;
|
private PwNode nodeToCopy;
|
||||||
private PwNode nodeToMove;
|
private PwNode nodeToMove;
|
||||||
|
|
||||||
private boolean entrySelectionMode;
|
|
||||||
private AutofillHelper autofillHelper;
|
|
||||||
|
|
||||||
private SearchEntryCursorAdapter searchSuggestionAdapter;
|
private SearchEntryCursorAdapter searchSuggestionAdapter;
|
||||||
|
|
||||||
private int iconColor;
|
private int iconColor;
|
||||||
|
|
||||||
private static void buildAndLaunchIntent(Activity activity, PwGroup group, boolean readOnly,
|
private static void buildAndLaunchIntent(Activity activity, PwGroup group, boolean readOnly,
|
||||||
IntentBuildLauncher intentBuildLauncher) {
|
IntentBuildLauncher intentBuildLauncher) {
|
||||||
if (TimeoutHelper.INSTANCE.checkTime(activity)) {
|
if (TimeoutHelper.INSTANCE.checkTimeAndLockIfTimeout(activity)) {
|
||||||
Intent intent = new Intent(activity, GroupActivity.class);
|
Intent intent = new Intent(activity, GroupActivity.class);
|
||||||
if (group != null) {
|
if (group != null) {
|
||||||
intent.putExtra(GROUP_ID_KEY, group.getId());
|
intent.putExtra(GROUP_ID_KEY, group.getId());
|
||||||
@@ -157,17 +158,16 @@ public class GroupActivity extends LockingActivity
|
|||||||
* -------------------------
|
* -------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// After a database creation
|
public static void launch(Activity activity) {
|
||||||
public static void launch(Activity act) {
|
launch(activity, READ_ONLY_DEFAULT);
|
||||||
launch(act, READ_ONLY_DEFAULT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void launch(Activity act, boolean readOnly) {
|
public static void launch(Activity activity, boolean readOnly) {
|
||||||
TimeoutHelper.INSTANCE.recordTime(act);
|
launch(activity, null, readOnly);
|
||||||
launch(act, null, readOnly);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void launch(Activity activity, PwGroup group, boolean readOnly) {
|
public static void launch(Activity activity, PwGroup group, boolean readOnly) {
|
||||||
|
TimeoutHelper.INSTANCE.recordTime(activity);
|
||||||
buildAndLaunchIntent(activity, group, readOnly,
|
buildAndLaunchIntent(activity, group, readOnly,
|
||||||
(intent) -> activity.startActivityForResult(intent, 0));
|
(intent) -> activity.startActivityForResult(intent, 0));
|
||||||
}
|
}
|
||||||
@@ -179,16 +179,15 @@ public class GroupActivity extends LockingActivity
|
|||||||
* -------------------------
|
* -------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public static void launchForKeyboardResult(Activity activity, boolean readOnly) {
|
public static void launchForKeyboardSelection(Activity activity, boolean readOnly) {
|
||||||
TimeoutHelper.INSTANCE.recordTime(activity);
|
launchForKeyboardSelection(activity, null, readOnly);
|
||||||
launchForKeyboardResult(activity, null, readOnly);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void launchForKeyboardResult(Activity activity, PwGroup group, boolean readOnly) {
|
public static void launchForKeyboardSelection(Activity activity, PwGroup group, boolean readOnly) {
|
||||||
// TODO implement pre search to directly open the direct group
|
// TODO implement pre search to directly open the direct group
|
||||||
|
TimeoutHelper.INSTANCE.recordTime(activity);
|
||||||
buildAndLaunchIntent(activity, group, readOnly, (intent) -> {
|
buildAndLaunchIntent(activity, group, readOnly, (intent) -> {
|
||||||
EntrySelectionHelper.addEntrySelectionModeExtraInIntent(intent);
|
KeyboardHelper.INSTANCE.startActivityForKeyboardSelection(activity, intent);
|
||||||
activity.startActivityForResult(intent, EntrySelectionHelper.ENTRY_SELECTION_RESPONSE_REQUEST_CODE);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -199,26 +198,17 @@ public class GroupActivity extends LockingActivity
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||||
public static void launchForAutofillResult(Activity activity, AssistStructure assistStructure, boolean readOnly) {
|
public static void launchForAutofillResult(Activity activity, @NonNull AssistStructure assistStructure, boolean readOnly) {
|
||||||
if ( assistStructure != null ) {
|
|
||||||
TimeoutHelper.INSTANCE.recordTime(activity);
|
|
||||||
launchForAutofillResult(activity, null, assistStructure, readOnly);
|
launchForAutofillResult(activity, null, assistStructure, readOnly);
|
||||||
} else {
|
|
||||||
launch(activity, readOnly);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||||
public static void launchForAutofillResult(Activity activity, PwGroup group, AssistStructure assistStructure, boolean readOnly) {
|
public static void launchForAutofillResult(Activity activity, PwGroup group, @NonNull AssistStructure assistStructure, boolean readOnly) {
|
||||||
// TODO implement pre search to directly open the direct group
|
// TODO implement pre search to directly open the direct group
|
||||||
if ( assistStructure != null ) {
|
TimeoutHelper.INSTANCE.recordTime(activity);
|
||||||
buildAndLaunchIntent(activity, group, readOnly, (intent) -> {
|
buildAndLaunchIntent(activity, group, readOnly, (intent) -> {
|
||||||
AutofillHelper.addAssistStructureExtraInIntent(intent, assistStructure);
|
AutofillHelper.INSTANCE.startActivityForAutofillResult(activity, intent, assistStructure);
|
||||||
activity.startActivityForResult(intent, AutofillHelper.AUTOFILL_RESPONSE_REQUEST_CODE);
|
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
launch(activity, group, readOnly);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -316,13 +306,6 @@ public class GroupActivity extends LockingActivity
|
|||||||
addNodeButtonView.setAddEntryClickListener(v ->
|
addNodeButtonView.setAddEntryClickListener(v ->
|
||||||
EntryEditActivity.launch(GroupActivity.this, mCurrentGroup));
|
EntryEditActivity.launch(GroupActivity.this, mCurrentGroup));
|
||||||
|
|
||||||
// To init autofill
|
|
||||||
entrySelectionMode = EntrySelectionHelper.isIntentInEntrySelectionMode(getIntent());
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
||||||
autofillHelper = new AutofillHelper();
|
|
||||||
autofillHelper.retrieveAssistStructure(getIntent());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Search suggestion
|
// Search suggestion
|
||||||
searchSuggestionAdapter = new SearchEntryCursorAdapter(this, database);
|
searchSuggestionAdapter = new SearchEntryCursorAdapter(this, database);
|
||||||
|
|
||||||
@@ -507,47 +490,46 @@ public class GroupActivity extends LockingActivity
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onNodeClick(PwNode node) {
|
public void onNodeClick(PwNode node) {
|
||||||
|
|
||||||
// Add event when we have Autofill
|
|
||||||
AssistStructure assistStructure = null;
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
||||||
assistStructure = autofillHelper.getAssistStructure();
|
|
||||||
if (assistStructure != null) {
|
|
||||||
switch (node.getType()) {
|
switch (node.getType()) {
|
||||||
case GROUP:
|
case GROUP:
|
||||||
|
try {
|
||||||
openChildGroup((PwGroup) node);
|
openChildGroup((PwGroup) node);
|
||||||
|
} catch (ClassCastException e) {
|
||||||
|
Log.e(TAG, "Node can't be cast in Group");
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case ENTRY:
|
case ENTRY:
|
||||||
|
try {
|
||||||
|
PwEntry entry = ((PwEntry) node);
|
||||||
|
EntrySelectionHelper.INSTANCE.doEntrySelectionAction(getIntent(),
|
||||||
|
() -> {
|
||||||
|
EntryActivity.launch(GroupActivity.this, entry, getReadOnly());
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
() -> {
|
||||||
|
MagikIME.setEntryKey(entry.getEntry());
|
||||||
|
// Show the notification if allowed in Preferences
|
||||||
|
if (PreferencesUtil.enableKeyboardNotificationEntry(GroupActivity.this)) {
|
||||||
|
Intent notificationIntent = new Intent(GroupActivity.this, KeyboardEntryNotificationService.class);
|
||||||
|
startService(notificationIntent);
|
||||||
|
}
|
||||||
|
moveTaskToBack(true);
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
assistStructure -> {
|
||||||
// Build response with the entry selected
|
// Build response with the entry selected
|
||||||
autofillHelper.buildResponseWhenEntrySelected(this, (PwEntry) node);
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
AutofillHelper.INSTANCE.buildResponseWhenEntrySelected(GroupActivity.this, entry);
|
||||||
|
}
|
||||||
finish();
|
finish();
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
} catch (ClassCastException e) {
|
||||||
|
Log.e(TAG, "Node can't be cast in Entry");
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if ( assistStructure == null ){
|
|
||||||
if (entrySelectionMode) {
|
|
||||||
switch (node.getType()) {
|
|
||||||
case GROUP:
|
|
||||||
openChildGroup((PwGroup) node);
|
|
||||||
break;
|
|
||||||
case ENTRY:
|
|
||||||
EntrySelectionHelper.buildResponseWhenEntrySelected(this, (PwEntry) node);
|
|
||||||
finish();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
switch (node.getType()) {
|
|
||||||
case GROUP:
|
|
||||||
openChildGroup((PwGroup) node);
|
|
||||||
break;
|
|
||||||
case ENTRY:
|
|
||||||
EntryActivity.launch(this, (PwEntry) node, getReadOnly());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onOpenMenuClick(PwNode node) {
|
public boolean onOpenMenuClick(PwNode node) {
|
||||||
@@ -920,7 +902,6 @@ public class GroupActivity extends LockingActivity
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void startActivity(Intent intent) {
|
public void startActivity(Intent intent) {
|
||||||
boolean customSearchQueryExecuted = false;
|
|
||||||
|
|
||||||
// Get the intent, verify the action and get the query
|
// Get the intent, verify the action and get the query
|
||||||
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
|
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
|
||||||
@@ -931,22 +912,26 @@ public class GroupActivity extends LockingActivity
|
|||||||
searchIntent.setAction(Intent.ACTION_SEARCH);
|
searchIntent.setAction(Intent.ACTION_SEARCH);
|
||||||
searchIntent.putExtra(SearchManager.QUERY, query);
|
searchIntent.putExtra(SearchManager.QUERY, query);
|
||||||
|
|
||||||
if ( Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
|
EntrySelectionHelper.INSTANCE.doEntrySelectionAction(intent,
|
||||||
&& autofillHelper.getAssistStructure() != null ) {
|
() -> {
|
||||||
AutofillHelper.addAssistStructureExtraInIntent(searchIntent, autofillHelper.getAssistStructure());
|
GroupActivity.super.startActivity(intent);
|
||||||
startActivityForResult(searchIntent, AutofillHelper.AUTOFILL_RESPONSE_REQUEST_CODE);
|
return null;
|
||||||
customSearchQueryExecuted = true;
|
},
|
||||||
|
() -> {
|
||||||
|
KeyboardHelper.INSTANCE.startActivityForKeyboardSelection(
|
||||||
|
GroupActivity.this,
|
||||||
|
searchIntent);
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
assistStructure -> {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
AutofillHelper.INSTANCE.startActivityForAutofillResult(
|
||||||
|
GroupActivity.this,
|
||||||
|
searchIntent,
|
||||||
|
assistStructure);
|
||||||
}
|
}
|
||||||
// To get the keyboard response, verify if the current intent contains the EntrySelection key
|
return null;
|
||||||
else if (EntrySelectionHelper.isIntentInEntrySelectionMode(getIntent())){
|
});
|
||||||
EntrySelectionHelper.addEntrySelectionModeExtraInIntent(searchIntent);
|
|
||||||
startActivityForResult(searchIntent, EntrySelectionHelper.ENTRY_SELECTION_RESPONSE_REQUEST_CODE);
|
|
||||||
customSearchQueryExecuted = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!customSearchQueryExecuted) {
|
|
||||||
super.startActivity(intent);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1179,9 +1164,8 @@ public class GroupActivity extends LockingActivity
|
|||||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
super.onActivityResult(requestCode, resultCode, data);
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
|
|
||||||
EntrySelectionHelper.onActivityResultSetResultAndFinish(this, requestCode, resultCode, data);
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
AutofillHelper.onActivityResultSetResultAndFinish(this, requestCode, resultCode, data);
|
AutofillHelper.INSTANCE.onActivityResultSetResultAndFinish(this, requestCode, resultCode, data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ abstract class LockingActivity : StylishActivity() {
|
|||||||
// After the first creation
|
// After the first creation
|
||||||
// or If simply swipe with another application
|
// or If simply swipe with another application
|
||||||
// If the time is out -> close the Activity
|
// If the time is out -> close the Activity
|
||||||
TimeoutHelper.checkTime(this)
|
TimeoutHelper.checkTimeAndLockIfTimeout(this)
|
||||||
// If onCreate already record time
|
// If onCreate already record time
|
||||||
if (!exitLock)
|
if (!exitLock)
|
||||||
TimeoutHelper.recordTime(this)
|
TimeoutHelper.recordTime(this)
|
||||||
@@ -121,7 +121,7 @@ abstract class LockingActivity : StylishActivity() {
|
|||||||
|
|
||||||
if (timeoutEnable) {
|
if (timeoutEnable) {
|
||||||
// If the time is out during our navigation in activity -> close the Activity
|
// If the time is out during our navigation in activity -> close the Activity
|
||||||
TimeoutHelper.checkTime(this)
|
TimeoutHelper.checkTimeAndLockIfTimeout(this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2017 Jeremy Jamet / Kunzisoft.
|
* Copyright 2019 Jeremy Jamet / Kunzisoft.
|
||||||
*
|
*
|
||||||
* This file is part of KeePass DX.
|
* This file is part of KeePass DX.
|
||||||
*
|
*
|
||||||
@@ -34,12 +34,12 @@ import com.kunzisoft.keepass.fileselect.FileSelectActivity
|
|||||||
import com.kunzisoft.keepass.timeout.TimeoutHelper
|
import com.kunzisoft.keepass.timeout.TimeoutHelper
|
||||||
|
|
||||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||||
class AutoFillAuthActivity : AppCompatActivity() {
|
class AutoFillLauncherActivity : AppCompatActivity() {
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
TimeoutHelper.checkTime(this) {}
|
|
||||||
// Pass extra for Autofill (EXTRA_ASSIST_STRUCTURE)
|
// Pass extra for Autofill (EXTRA_ASSIST_STRUCTURE)
|
||||||
val assistStructure = AutofillHelper().retrieveAssistStructure(intent)
|
TimeoutHelper.checkTime(this)
|
||||||
|
val assistStructure = AutofillHelper.retrieveAssistStructure(intent)
|
||||||
if (assistStructure != null) {
|
if (assistStructure != null) {
|
||||||
if (App.getDB().loaded)
|
if (App.getDB().loaded)
|
||||||
GroupActivity.launchForAutofillResult(this, assistStructure, true)
|
GroupActivity.launchForAutofillResult(this, assistStructure, true)
|
||||||
@@ -54,14 +54,14 @@ class AutoFillAuthActivity : AppCompatActivity() {
|
|||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
|
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||||
AutofillHelper.onActivityResultSetResultAndFinish(this, requestCode, resultCode, data)
|
AutofillHelper.onActivityResultSetResultAndFinish(this, requestCode, resultCode, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
fun getAuthIntentSenderForResponse(context: Context): IntentSender {
|
fun getAuthIntentSenderForResponse(context: Context): IntentSender {
|
||||||
val intent = Intent(context, AutoFillAuthActivity::class.java)
|
val intent = Intent(context, AutoFillLauncherActivity::class.java)
|
||||||
return PendingIntent.getActivity(context, 0,
|
return PendingIntent.getActivity(context, 0,
|
||||||
intent, PendingIntent.FLAG_CANCEL_CURRENT).intentSender
|
intent, PendingIntent.FLAG_CANCEL_CURRENT).intentSender
|
||||||
}
|
}
|
||||||
@@ -1,167 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
|
|
||||||
*
|
|
||||||
* This file is part of KeePass DX.
|
|
||||||
*
|
|
||||||
* KeePass DX is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* KeePass DX is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with KeePass DX. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
package com.kunzisoft.keepass.autofill;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.app.assist.AssistStructure;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.service.autofill.Dataset;
|
|
||||||
import android.service.autofill.FillResponse;
|
|
||||||
import android.support.annotation.Nullable;
|
|
||||||
import android.support.annotation.RequiresApi;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.view.autofill.AutofillId;
|
|
||||||
import android.view.autofill.AutofillManager;
|
|
||||||
import android.view.autofill.AutofillValue;
|
|
||||||
import android.widget.RemoteViews;
|
|
||||||
|
|
||||||
import com.kunzisoft.keepass.R;
|
|
||||||
import com.kunzisoft.keepass.database.PwEntry;
|
|
||||||
import com.kunzisoft.keepass.selection.EntrySelectionHelper;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
|
|
||||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
|
||||||
public class AutofillHelper {
|
|
||||||
|
|
||||||
public static final int AUTOFILL_RESPONSE_REQUEST_CODE = 8165;
|
|
||||||
|
|
||||||
private AssistStructure assistStructure = null;
|
|
||||||
|
|
||||||
public AssistStructure retrieveAssistStructure(Intent intent) {
|
|
||||||
if (intent != null && intent.getExtras() != null) {
|
|
||||||
assistStructure = intent.getParcelableExtra(android.view.autofill.AutofillManager.EXTRA_ASSIST_STRUCTURE);
|
|
||||||
}
|
|
||||||
return assistStructure;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Call retrieveAssistStructure before
|
|
||||||
*/
|
|
||||||
public AssistStructure getAssistStructure() {
|
|
||||||
return assistStructure;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void addAssistStructureExtraInIntent(Intent intent, AssistStructure assistStructure) {
|
|
||||||
if (assistStructure != null) {
|
|
||||||
EntrySelectionHelper.addEntrySelectionModeExtraInIntent(intent);
|
|
||||||
intent.putExtra(android.view.autofill.AutofillManager.EXTRA_ASSIST_STRUCTURE, assistStructure);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Define if android.view.autofill.AutofillManager.EXTRA_ASSIST_STRUCTURE is an extra bundle key present in the Intent
|
|
||||||
*/
|
|
||||||
public static boolean isIntentContainsExtraAssistStructureKey(Intent intent) {
|
|
||||||
return (intent != null
|
|
||||||
&& intent.getExtras() != null
|
|
||||||
&& intent.getExtras().containsKey(android.view.autofill.AutofillManager.EXTRA_ASSIST_STRUCTURE));
|
|
||||||
}
|
|
||||||
|
|
||||||
private @Nullable Dataset buildDataset(Context context, PwEntry entry,
|
|
||||||
StructureParser.Result struct) {
|
|
||||||
String title = makeEntryTitle(entry);
|
|
||||||
RemoteViews views = newRemoteViews(context.getPackageName(), title);
|
|
||||||
Dataset.Builder builder = new Dataset.Builder(views);
|
|
||||||
builder.setId(entry.getUUID().toString());
|
|
||||||
|
|
||||||
if (entry.getPassword() != null) {
|
|
||||||
AutofillValue value = AutofillValue.forText(entry.getPassword());
|
|
||||||
struct.password.forEach(id -> builder.setValue(id, value));
|
|
||||||
}
|
|
||||||
if (entry.getUsername() != null) {
|
|
||||||
AutofillValue value = AutofillValue.forText(entry.getUsername());
|
|
||||||
List<AutofillId> ids = new ArrayList<>(struct.username);
|
|
||||||
if (entry.getUsername().contains("@") || struct.username.isEmpty())
|
|
||||||
ids.addAll(struct.email);
|
|
||||||
ids.forEach(id -> builder.setValue(id, value));
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return builder.build();
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
// if not value be set
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static private String makeEntryTitle(PwEntry entry) {
|
|
||||||
if (!entry.getTitle().isEmpty() && !entry.getUsername().isEmpty())
|
|
||||||
return String.format("%s (%s)", entry.getTitle(), entry.getUsername());
|
|
||||||
if (!entry.getTitle().isEmpty())
|
|
||||||
return entry.getTitle();
|
|
||||||
if (!entry.getUsername().isEmpty())
|
|
||||||
return entry.getUsername();
|
|
||||||
if (!entry.getNotes().isEmpty())
|
|
||||||
return entry.getNotes().trim();
|
|
||||||
return ""; // TODO No title
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method to hit when right key is selected
|
|
||||||
*/
|
|
||||||
public void buildResponseWhenEntrySelected(Activity activity, PwEntry entry) {
|
|
||||||
Intent mReplyIntent;
|
|
||||||
Intent intent = activity.getIntent();
|
|
||||||
if (isIntentContainsExtraAssistStructureKey(intent)) {
|
|
||||||
AssistStructure structure = intent.getParcelableExtra(android.view.autofill.AutofillManager.EXTRA_ASSIST_STRUCTURE);
|
|
||||||
StructureParser.Result result = new StructureParser(structure).parse();
|
|
||||||
|
|
||||||
// New Response
|
|
||||||
FillResponse.Builder responseBuilder = new FillResponse.Builder();
|
|
||||||
Dataset dataset = buildDataset(activity, entry, result);
|
|
||||||
responseBuilder.addDataset(dataset);
|
|
||||||
mReplyIntent = new Intent();
|
|
||||||
Log.d(activity.getClass().getName(), "Successed Autofill auth.");
|
|
||||||
mReplyIntent.putExtra(
|
|
||||||
AutofillManager.EXTRA_AUTHENTICATION_RESULT,
|
|
||||||
responseBuilder.build());
|
|
||||||
activity.setResult(Activity.RESULT_OK, mReplyIntent);
|
|
||||||
} else {
|
|
||||||
Log.w(activity.getClass().getName(), "Failed Autofill auth.");
|
|
||||||
activity.setResult(Activity.RESULT_CANCELED);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Utility method to loop and close each activity with return data
|
|
||||||
*/
|
|
||||||
public static void onActivityResultSetResultAndFinish(Activity activity, int requestCode, int resultCode, Intent data) {
|
|
||||||
if (requestCode == AUTOFILL_RESPONSE_REQUEST_CODE) {
|
|
||||||
if (resultCode == Activity.RESULT_OK) {
|
|
||||||
activity.setResult(resultCode, data);
|
|
||||||
}
|
|
||||||
if (resultCode == Activity.RESULT_CANCELED) {
|
|
||||||
activity.setResult(Activity.RESULT_CANCELED);
|
|
||||||
}
|
|
||||||
activity.finish();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static RemoteViews newRemoteViews(String packageName, String remoteViewsText) {
|
|
||||||
RemoteViews presentation =
|
|
||||||
new RemoteViews(packageName, R.layout.autofill_service_list_item);
|
|
||||||
presentation.setTextViewText(R.id.text, remoteViewsText);
|
|
||||||
return presentation;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,147 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2019 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/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package com.kunzisoft.keepass.autofill
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.app.assist.AssistStructure
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Build
|
||||||
|
import android.service.autofill.Dataset
|
||||||
|
import android.service.autofill.FillResponse
|
||||||
|
import android.support.annotation.RequiresApi
|
||||||
|
import android.util.Log
|
||||||
|
import android.view.autofill.AutofillManager
|
||||||
|
import android.view.autofill.AutofillValue
|
||||||
|
import android.widget.RemoteViews
|
||||||
|
import com.kunzisoft.keepass.R
|
||||||
|
import com.kunzisoft.keepass.database.PwEntry
|
||||||
|
import com.kunzisoft.keepass.selection.EntrySelectionHelper
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
|
||||||
|
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||||
|
object AutofillHelper {
|
||||||
|
|
||||||
|
private const val AUTOFILL_RESPONSE_REQUEST_CODE = 8165
|
||||||
|
|
||||||
|
private const val ASSIST_STRUCTURE = android.view.autofill.AutofillManager.EXTRA_ASSIST_STRUCTURE
|
||||||
|
|
||||||
|
fun retrieveAssistStructure(intent: Intent?): AssistStructure? {
|
||||||
|
intent?.let {
|
||||||
|
return it.getParcelableExtra(ASSIST_STRUCTURE)
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun makeEntryTitle(entry: PwEntry<*>): String {
|
||||||
|
if (!entry.title.isEmpty() && !entry.username.isEmpty())
|
||||||
|
return String.format("%s (%s)", entry.title, entry.username)
|
||||||
|
if (!entry.title.isEmpty())
|
||||||
|
return entry.title
|
||||||
|
if (!entry.username.isEmpty())
|
||||||
|
return entry.username
|
||||||
|
return if (!entry.notes.isEmpty()) entry.notes.trim { it <= ' ' } else ""
|
||||||
|
// TODO No title
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun buildDataset(context: Context, entry: PwEntry<*>,
|
||||||
|
struct: StructureParser.Result): Dataset? {
|
||||||
|
val title = makeEntryTitle(entry)
|
||||||
|
val views = newRemoteViews(context.packageName, title)
|
||||||
|
val builder = Dataset.Builder(views)
|
||||||
|
builder.setId(entry.uuid.toString())
|
||||||
|
|
||||||
|
if (entry.password != null) {
|
||||||
|
val value = AutofillValue.forText(entry.password)
|
||||||
|
struct.password.forEach { id -> builder.setValue(id, value) }
|
||||||
|
}
|
||||||
|
if (entry.username != null) {
|
||||||
|
val value = AutofillValue.forText(entry.username)
|
||||||
|
val ids = ArrayList(struct.username)
|
||||||
|
if (entry.username.contains("@") || struct.username.isEmpty())
|
||||||
|
ids.addAll(struct.email)
|
||||||
|
ids.forEach { id -> builder.setValue(id, value) }
|
||||||
|
}
|
||||||
|
return try {
|
||||||
|
builder.build()
|
||||||
|
} catch (e: IllegalArgumentException) {
|
||||||
|
// if not value be set
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to hit when right key is selected
|
||||||
|
*/
|
||||||
|
fun buildResponseWhenEntrySelected(activity: Activity, entry: PwEntry<*>) {
|
||||||
|
val mReplyIntent: Intent
|
||||||
|
activity.intent?.let { intent ->
|
||||||
|
if (intent.extras.containsKey(ASSIST_STRUCTURE)) {
|
||||||
|
val structure = intent.getParcelableExtra<AssistStructure>(ASSIST_STRUCTURE)
|
||||||
|
val result = StructureParser(structure).parse()
|
||||||
|
|
||||||
|
// New Response
|
||||||
|
val responseBuilder = FillResponse.Builder()
|
||||||
|
val dataset = buildDataset(activity, entry, result)
|
||||||
|
responseBuilder.addDataset(dataset)
|
||||||
|
mReplyIntent = Intent()
|
||||||
|
Log.d(activity.javaClass.name, "Successed Autofill auth.")
|
||||||
|
mReplyIntent.putExtra(
|
||||||
|
AutofillManager.EXTRA_AUTHENTICATION_RESULT,
|
||||||
|
responseBuilder.build())
|
||||||
|
activity.setResult(Activity.RESULT_OK, mReplyIntent)
|
||||||
|
} else {
|
||||||
|
Log.w(activity.javaClass.name, "Failed Autofill auth.")
|
||||||
|
activity.setResult(Activity.RESULT_CANCELED)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility method to start an activity with an Autofill for result
|
||||||
|
*/
|
||||||
|
fun startActivityForAutofillResult(activity: Activity, intent: Intent, assistStructure: AssistStructure) {
|
||||||
|
EntrySelectionHelper.addEntrySelectionModeExtraInIntent(intent)
|
||||||
|
intent.putExtra(ASSIST_STRUCTURE, assistStructure)
|
||||||
|
activity.startActivityForResult(intent, AutofillHelper.AUTOFILL_RESPONSE_REQUEST_CODE)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility method to loop and close each activity with return data
|
||||||
|
*/
|
||||||
|
fun onActivityResultSetResultAndFinish(activity: Activity, requestCode: Int, resultCode: Int, data: Intent?) {
|
||||||
|
if (requestCode == AUTOFILL_RESPONSE_REQUEST_CODE) {
|
||||||
|
if (resultCode == Activity.RESULT_OK) {
|
||||||
|
activity.setResult(resultCode, data)
|
||||||
|
}
|
||||||
|
if (resultCode == Activity.RESULT_CANCELED) {
|
||||||
|
activity.setResult(Activity.RESULT_CANCELED)
|
||||||
|
}
|
||||||
|
activity.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun newRemoteViews(packageName: String, remoteViewsText: String): RemoteViews {
|
||||||
|
val presentation = RemoteViews(packageName, R.layout.autofill_service_list_item)
|
||||||
|
presentation.setTextViewText(R.id.text, remoteViewsText)
|
||||||
|
return presentation
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -62,7 +62,7 @@ public class KeeAutofillService extends AutofillService {
|
|||||||
if (!Arrays.asList(autofillIds).isEmpty()) {
|
if (!Arrays.asList(autofillIds).isEmpty()) {
|
||||||
// If the entire Autofill Response is authenticated, AuthActivity is used
|
// If the entire Autofill Response is authenticated, AuthActivity is used
|
||||||
// to generate Response.
|
// to generate Response.
|
||||||
IntentSender sender = AutoFillAuthActivity.Companion.getAuthIntentSenderForResponse(this);
|
IntentSender sender = AutoFillLauncherActivity.Companion.getAuthIntentSenderForResponse(this);
|
||||||
RemoteViews presentation = new RemoteViews(getPackageName(), R.layout.autofill_service_unlock);
|
RemoteViews presentation = new RemoteViews(getPackageName(), R.layout.autofill_service_unlock);
|
||||||
responseBuilder.setAuthentication(autofillIds, sender, presentation);
|
responseBuilder.setAuthentication(autofillIds, sender, presentation);
|
||||||
callback.onSuccess(responseBuilder.build());
|
callback.onSuccess(responseBuilder.build());
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ import android.os.Parcel;
|
|||||||
|
|
||||||
import com.kunzisoft.keepass.database.iterator.EntrySearchStringIterator;
|
import com.kunzisoft.keepass.database.iterator.EntrySearchStringIterator;
|
||||||
import com.kunzisoft.keepass.database.security.ProtectedString;
|
import com.kunzisoft.keepass.database.security.ProtectedString;
|
||||||
|
import com.kunzisoft.keepass.model.Entry;
|
||||||
|
import com.kunzisoft.keepass.model.Field;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@@ -199,6 +201,21 @@ public abstract class PwEntry<Parent extends PwGroup> extends PwNode<Parent> {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Entry getEntry() {
|
||||||
|
Entry entryModel = new Entry();
|
||||||
|
entryModel.setTitle(getTitle());
|
||||||
|
entryModel.setUsername(getUsername());
|
||||||
|
entryModel.setPassword(getPassword());
|
||||||
|
entryModel.setUrl(getUrl());
|
||||||
|
if (containsCustomFields()) {
|
||||||
|
getFields()
|
||||||
|
.doActionToAllCustomProtectedField(
|
||||||
|
(key, value) -> entryModel.addCustomField(
|
||||||
|
new Field(key, value.toString())));
|
||||||
|
}
|
||||||
|
return entryModel;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) return true;
|
||||||
|
|||||||
@@ -53,9 +53,9 @@ import com.kunzisoft.keepass.app.App;
|
|||||||
import com.kunzisoft.keepass.autofill.AutofillHelper;
|
import com.kunzisoft.keepass.autofill.AutofillHelper;
|
||||||
import com.kunzisoft.keepass.database.action.CreateDatabaseRunnable;
|
import com.kunzisoft.keepass.database.action.CreateDatabaseRunnable;
|
||||||
import com.kunzisoft.keepass.database.action.FileOnFinishRunnable;
|
import com.kunzisoft.keepass.database.action.FileOnFinishRunnable;
|
||||||
import com.kunzisoft.keepass.database.exception.ContentFileNotFoundException;
|
|
||||||
import com.kunzisoft.keepass.dialogs.AssignMasterKeyDialogFragment;
|
import com.kunzisoft.keepass.dialogs.AssignMasterKeyDialogFragment;
|
||||||
import com.kunzisoft.keepass.dialogs.CreateFileDialogFragment;
|
import com.kunzisoft.keepass.dialogs.CreateFileDialogFragment;
|
||||||
|
import com.kunzisoft.keepass.magikeyboard.KeyboardHelper;
|
||||||
import com.kunzisoft.keepass.password.AssignPasswordHelper;
|
import com.kunzisoft.keepass.password.AssignPasswordHelper;
|
||||||
import com.kunzisoft.keepass.password.PasswordActivity;
|
import com.kunzisoft.keepass.password.PasswordActivity;
|
||||||
import com.kunzisoft.keepass.selection.EntrySelectionHelper;
|
import com.kunzisoft.keepass.selection.EntrySelectionHelper;
|
||||||
@@ -104,9 +104,6 @@ public class FileSelectActivity extends StylishActivity implements
|
|||||||
// TODO Consultation Mode
|
// TODO Consultation Mode
|
||||||
private boolean consultationMode = false;
|
private boolean consultationMode = false;
|
||||||
|
|
||||||
private boolean entrySelectionMode;
|
|
||||||
private AutofillHelper autofillHelper;
|
|
||||||
|
|
||||||
private View fileSelectExpandableButton;
|
private View fileSelectExpandableButton;
|
||||||
private ExpandableLayout fileSelectExpandable;
|
private ExpandableLayout fileSelectExpandable;
|
||||||
private EditText openFileNameView;
|
private EditText openFileNameView;
|
||||||
@@ -118,27 +115,33 @@ public class FileSelectActivity extends StylishActivity implements
|
|||||||
|
|
||||||
private String defaultPath;
|
private String defaultPath;
|
||||||
|
|
||||||
public static void launch(Activity activity) {
|
/*
|
||||||
Intent intent = new Intent(activity, FileSelectActivity.class);
|
* -------------------------
|
||||||
// only to avoid visible flickering when redirecting
|
* No Standard Launch, pass by PasswordActivity
|
||||||
activity.startActivityForResult(intent, RESULT_CANCELED);
|
* -------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* -------------------------
|
||||||
|
* Keyboard Launch
|
||||||
|
* -------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
public static void launchForKeyboardSelection(Activity activity) {
|
||||||
|
KeyboardHelper.INSTANCE.startActivityForKeyboardSelection(activity, new Intent(activity, FileSelectActivity.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void launchForKeyboardResult(Activity activity) {
|
/*
|
||||||
Intent intent = new Intent(activity, FileSelectActivity.class);
|
* -------------------------
|
||||||
EntrySelectionHelper.addEntrySelectionModeExtraInIntent(intent);
|
* Autofill Launch
|
||||||
activity.startActivityForResult(intent, EntrySelectionHelper.ENTRY_SELECTION_RESPONSE_REQUEST_CODE);
|
* -------------------------
|
||||||
}
|
*/
|
||||||
|
|
||||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||||
public static void launchForAutofillResult(Activity activity, AssistStructure assistStructure) {
|
public static void launchForAutofillResult(Activity activity, @NonNull AssistStructure assistStructure) {
|
||||||
if ( assistStructure != null ) {
|
AutofillHelper.INSTANCE.startActivityForAutofillResult(activity,
|
||||||
Intent intent = new Intent(activity, FileSelectActivity.class);
|
new Intent(activity, FileSelectActivity.class),
|
||||||
AutofillHelper.addAssistStructureExtraInIntent(intent, assistStructure);
|
assistStructure);
|
||||||
activity.startActivityForResult(intent, AutofillHelper.AUTOFILL_RESPONSE_REQUEST_CODE);
|
|
||||||
} else {
|
|
||||||
launch(activity);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -177,13 +180,6 @@ public class FileSelectActivity extends StylishActivity implements
|
|||||||
RecyclerView mListFiles = findViewById(R.id.file_list);
|
RecyclerView mListFiles = findViewById(R.id.file_list);
|
||||||
mListFiles.setLayoutManager(new LinearLayoutManager(this));
|
mListFiles.setLayoutManager(new LinearLayoutManager(this));
|
||||||
|
|
||||||
entrySelectionMode = EntrySelectionHelper.isIntentInEntrySelectionMode(getIntent());
|
|
||||||
// To retrieve info for AutoFill
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
||||||
autofillHelper = new AutofillHelper();
|
|
||||||
autofillHelper.retrieveAssistStructure(getIntent());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Open button
|
// Open button
|
||||||
openButtonView = findViewById(R.id.open_database);
|
openButtonView = findViewById(R.id.open_database);
|
||||||
openButtonView.setOnClickListener(v -> {
|
openButtonView.setOnClickListener(v -> {
|
||||||
@@ -243,40 +239,52 @@ public class FileSelectActivity extends StylishActivity implements
|
|||||||
checkAndPerformedEducation();
|
checkAndPerformedEducation();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void launchPasswordActivityWithPath(String path) {
|
private void fileNoFoundAction(FileNotFoundException e) {
|
||||||
try {
|
|
||||||
AssistStructure assistStructure = null;
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
||||||
assistStructure = autofillHelper.getAssistStructure();
|
|
||||||
if (assistStructure != null) {
|
|
||||||
PasswordActivity.launchForAutofillResult(FileSelectActivity.this,
|
|
||||||
path,
|
|
||||||
assistStructure);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (assistStructure == null) {
|
|
||||||
if (entrySelectionMode) {
|
|
||||||
PasswordActivity.launchForKeyboardResult(FileSelectActivity.this, path);
|
|
||||||
} else {
|
|
||||||
PasswordActivity.launch(FileSelectActivity.this, path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Delete flickering for kitkat <=
|
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP)
|
|
||||||
overridePendingTransition(0, 0);
|
|
||||||
} catch (ContentFileNotFoundException e) {
|
|
||||||
String error = getString(R.string.file_not_found_content);
|
String error = getString(R.string.file_not_found_content);
|
||||||
Toast.makeText(FileSelectActivity.this,
|
Toast.makeText(FileSelectActivity.this,
|
||||||
error, Toast.LENGTH_LONG).show();
|
error, Toast.LENGTH_LONG).show();
|
||||||
Log.e(TAG, error, e);
|
Log.e(TAG, error, e);
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
String error = getString(R.string.file_not_found);
|
|
||||||
Toast.makeText(FileSelectActivity.this,
|
|
||||||
error, Toast.LENGTH_LONG).show();
|
|
||||||
Log.e(TAG, error, e);
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.e(TAG, "Can't launch PasswordActivity", e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void launchPasswordActivity(String fileName, String keyFile) {
|
||||||
|
EntrySelectionHelper.INSTANCE.doEntrySelectionAction(getIntent(),
|
||||||
|
() -> {
|
||||||
|
try {
|
||||||
|
PasswordActivity.launch(FileSelectActivity.this,
|
||||||
|
fileName, keyFile);
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
fileNoFoundAction(e);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
() -> {
|
||||||
|
try {
|
||||||
|
PasswordActivity.launchForKeyboardResult(FileSelectActivity.this,
|
||||||
|
fileName, keyFile);
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
fileNoFoundAction(e);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
assistStructure -> {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
try {
|
||||||
|
PasswordActivity.launchForAutofillResult(FileSelectActivity.this,
|
||||||
|
fileName, keyFile,
|
||||||
|
assistStructure);
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
fileNoFoundAction(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void launchPasswordActivityWithPath(String path) {
|
||||||
|
launchPasswordActivity(path, "");
|
||||||
|
// Delete flickering for kitkat <=
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP)
|
||||||
|
overridePendingTransition(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateExternalStorageWarning() {
|
private void updateExternalStorageWarning() {
|
||||||
@@ -603,32 +611,7 @@ public class FileSelectActivity extends StylishActivity implements
|
|||||||
@Override
|
@Override
|
||||||
public void onFileItemOpenListener(int itemPosition) {
|
public void onFileItemOpenListener(int itemPosition) {
|
||||||
new OpenFileHistoryAsyncTask((fileName, keyFile) -> {
|
new OpenFileHistoryAsyncTask((fileName, keyFile) -> {
|
||||||
// TODO ENCAPSULATE
|
launchPasswordActivity(fileName, keyFile);
|
||||||
try {
|
|
||||||
AssistStructure assistStructure = null;
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
||||||
assistStructure = autofillHelper.getAssistStructure();
|
|
||||||
if (assistStructure != null) {
|
|
||||||
PasswordActivity.launchForAutofillResult(FileSelectActivity.this,
|
|
||||||
fileName, keyFile, assistStructure);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (assistStructure == null) {
|
|
||||||
if (entrySelectionMode) {
|
|
||||||
PasswordActivity.launchForKeyboardResult(FileSelectActivity.this, fileName, keyFile);
|
|
||||||
} else {
|
|
||||||
PasswordActivity.launch(FileSelectActivity.this, fileName, keyFile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (ContentFileNotFoundException e) {
|
|
||||||
Toast.makeText(FileSelectActivity.this,
|
|
||||||
R.string.file_not_found_content, Toast.LENGTH_LONG)
|
|
||||||
.show();
|
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
Toast.makeText(FileSelectActivity.this,
|
|
||||||
R.string.file_not_found, Toast.LENGTH_LONG)
|
|
||||||
.show();
|
|
||||||
}
|
|
||||||
updateFileListVisibility();
|
updateFileListVisibility();
|
||||||
}, fileHistory).execute(itemPosition);
|
}, fileHistory).execute(itemPosition);
|
||||||
}
|
}
|
||||||
@@ -656,10 +639,8 @@ public class FileSelectActivity extends StylishActivity implements
|
|||||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
super.onActivityResult(requestCode, resultCode, data);
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
|
|
||||||
// Get the entry result in entry selection mode
|
|
||||||
EntrySelectionHelper.onActivityResultSetResultAndFinish(this, requestCode, resultCode, data);
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
AutofillHelper.onActivityResultSetResultAndFinish(this, requestCode, resultCode, data);
|
AutofillHelper.INSTANCE.onActivityResultSetResultAndFinish(this, requestCode, resultCode, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
keyFileHelper.onActivityResultCallback(requestCode, resultCode, data,
|
keyFileHelper.onActivityResultCallback(requestCode, resultCode, data,
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package com.kunzisoft.keepass.magikeyboard
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.content.Intent
|
||||||
|
import com.kunzisoft.keepass.selection.EntrySelectionHelper
|
||||||
|
|
||||||
|
object KeyboardHelper {
|
||||||
|
|
||||||
|
fun startActivityForKeyboardSelection(activity: Activity, intent: Intent) {
|
||||||
|
EntrySelectionHelper.addEntrySelectionModeExtraInIntent(intent)
|
||||||
|
// only to avoid visible flickering when redirecting
|
||||||
|
activity.startActivityForResult(intent, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package com.kunzisoft.keepass.magikeyboard
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.support.v7.app.AppCompatActivity
|
||||||
|
import com.kunzisoft.keepass.activities.GroupActivity
|
||||||
|
import com.kunzisoft.keepass.app.App
|
||||||
|
import com.kunzisoft.keepass.fileselect.FileSelectActivity
|
||||||
|
import com.kunzisoft.keepass.timeout.TimeoutHelper
|
||||||
|
|
||||||
|
class KeyboardLauncherActivity : AppCompatActivity() {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val TAG = KeyboardLauncherActivity::class.java.name!!
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
TimeoutHelper.checkTime(this)
|
||||||
|
if (App.getDB().loaded)
|
||||||
|
GroupActivity.launchForKeyboardSelection(this, true)
|
||||||
|
else {
|
||||||
|
// Pass extra to get entry
|
||||||
|
FileSelectActivity.launchForKeyboardSelection(this)
|
||||||
|
}
|
||||||
|
finish()
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -48,7 +48,6 @@ import com.kunzisoft.keepass.magikeyboard.adapter.FieldsAdapter;
|
|||||||
import com.kunzisoft.keepass.magikeyboard.receiver.LockBroadcastReceiver;
|
import com.kunzisoft.keepass.magikeyboard.receiver.LockBroadcastReceiver;
|
||||||
import com.kunzisoft.keepass.magikeyboard.view.MagikeyboardView;
|
import com.kunzisoft.keepass.magikeyboard.view.MagikeyboardView;
|
||||||
import com.kunzisoft.keepass.model.Entry;
|
import com.kunzisoft.keepass.model.Entry;
|
||||||
import com.kunzisoft.keepass.selection.KeyboardEntryRetrieverActivity;
|
|
||||||
|
|
||||||
import static com.kunzisoft.keepass.magikeyboard.receiver.LockBroadcastReceiver.LOCK_ACTION;
|
import static com.kunzisoft.keepass.magikeyboard.receiver.LockBroadcastReceiver.LOCK_ACTION;
|
||||||
|
|
||||||
@@ -206,8 +205,7 @@ public class MagikIME extends InputMethodService
|
|||||||
break;
|
break;
|
||||||
case KEY_ENTRY:
|
case KEY_ENTRY:
|
||||||
deleteEntryKey(this);
|
deleteEntryKey(this);
|
||||||
Intent intent = new Intent(this, KeyboardEntryRetrieverActivity.class);
|
Intent intent = new Intent(this, KeyboardLauncherActivity.class);
|
||||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
break;
|
break;
|
||||||
case KEY_LOCK:
|
case KEY_LOCK:
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ import com.kunzisoft.keepass.fileselect.KeyFileHelper;
|
|||||||
import com.kunzisoft.keepass.fingerprint.FingerPrintAnimatedVector;
|
import com.kunzisoft.keepass.fingerprint.FingerPrintAnimatedVector;
|
||||||
import com.kunzisoft.keepass.fingerprint.FingerPrintExplanationDialog;
|
import com.kunzisoft.keepass.fingerprint.FingerPrintExplanationDialog;
|
||||||
import com.kunzisoft.keepass.fingerprint.FingerPrintHelper;
|
import com.kunzisoft.keepass.fingerprint.FingerPrintHelper;
|
||||||
|
import com.kunzisoft.keepass.magikeyboard.KeyboardHelper;
|
||||||
import com.kunzisoft.keepass.selection.EntrySelectionHelper;
|
import com.kunzisoft.keepass.selection.EntrySelectionHelper;
|
||||||
import com.kunzisoft.keepass.settings.PreferencesUtil;
|
import com.kunzisoft.keepass.settings.PreferencesUtil;
|
||||||
import com.kunzisoft.keepass.stylish.StylishActivity;
|
import com.kunzisoft.keepass.stylish.StylishActivity;
|
||||||
@@ -133,9 +134,6 @@ public class PasswordActivity extends StylishActivity
|
|||||||
|
|
||||||
private KeyFileHelper keyFileHelper;
|
private KeyFileHelper keyFileHelper;
|
||||||
|
|
||||||
protected boolean entrySelectionMode;
|
|
||||||
private AutofillHelper autofillHelper;
|
|
||||||
|
|
||||||
private static void buildAndLaunchIntent(Activity activity, String fileName, String keyFile,
|
private static void buildAndLaunchIntent(Activity activity, String fileName, String keyFile,
|
||||||
IntentBuildLauncher intentBuildLauncher) {
|
IntentBuildLauncher intentBuildLauncher) {
|
||||||
Intent intent = new Intent(activity, PasswordActivity.class);
|
Intent intent = new Intent(activity, PasswordActivity.class);
|
||||||
@@ -167,12 +165,6 @@ public class PasswordActivity extends StylishActivity
|
|||||||
* -------------------------
|
* -------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public static void launch(
|
|
||||||
Activity act,
|
|
||||||
String fileName) throws FileNotFoundException {
|
|
||||||
launch(act, fileName, "");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void launch(
|
public static void launch(
|
||||||
Activity activity,
|
Activity activity,
|
||||||
String fileName,
|
String fileName,
|
||||||
@@ -187,12 +179,6 @@ public class PasswordActivity extends StylishActivity
|
|||||||
* -------------------------
|
* -------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public static void launchForKeyboardResult(
|
|
||||||
Activity act,
|
|
||||||
String fileName) throws FileNotFoundException {
|
|
||||||
launchForKeyboardResult(act, fileName, "");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void launchForKeyboardResult(
|
public static void launchForKeyboardResult(
|
||||||
Activity activity,
|
Activity activity,
|
||||||
String fileName,
|
String fileName,
|
||||||
@@ -200,9 +186,7 @@ public class PasswordActivity extends StylishActivity
|
|||||||
verifyFileNameUriFromLaunch(fileName);
|
verifyFileNameUriFromLaunch(fileName);
|
||||||
|
|
||||||
buildAndLaunchIntent(activity, fileName, keyFile, (intent) -> {
|
buildAndLaunchIntent(activity, fileName, keyFile, (intent) -> {
|
||||||
EntrySelectionHelper.addEntrySelectionModeExtraInIntent(intent);
|
KeyboardHelper.INSTANCE.startActivityForKeyboardSelection(activity, intent);
|
||||||
// only to avoid visible flickering when redirecting
|
|
||||||
activity.startActivityForResult(intent, EntrySelectionHelper.ENTRY_SELECTION_RESPONSE_REQUEST_CODE);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,14 +196,6 @@ public class PasswordActivity extends StylishActivity
|
|||||||
* -------------------------
|
* -------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
|
||||||
public static void launchForAutofillResult(
|
|
||||||
Activity act,
|
|
||||||
String fileName,
|
|
||||||
AssistStructure assistStructure) throws FileNotFoundException {
|
|
||||||
launchForAutofillResult(act, fileName, "", assistStructure);
|
|
||||||
}
|
|
||||||
|
|
||||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||||
public static void launchForAutofillResult(
|
public static void launchForAutofillResult(
|
||||||
Activity activity,
|
Activity activity,
|
||||||
@@ -230,8 +206,10 @@ public class PasswordActivity extends StylishActivity
|
|||||||
|
|
||||||
if ( assistStructure != null ) {
|
if ( assistStructure != null ) {
|
||||||
buildAndLaunchIntent(activity, fileName, keyFile, (intent) -> {
|
buildAndLaunchIntent(activity, fileName, keyFile, (intent) -> {
|
||||||
AutofillHelper.addAssistStructureExtraInIntent(intent, assistStructure);
|
AutofillHelper.INSTANCE.startActivityForAutofillResult(
|
||||||
activity.startActivityForResult(intent, AutofillHelper.AUTOFILL_RESPONSE_REQUEST_CODE);
|
activity,
|
||||||
|
intent,
|
||||||
|
assistStructure);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
launch(activity, fileName, keyFile);
|
launch(activity, fileName, keyFile);
|
||||||
@@ -310,13 +288,6 @@ public class PasswordActivity extends StylishActivity
|
|||||||
fingerPrintAnimatedVector = new FingerPrintAnimatedVector(this,
|
fingerPrintAnimatedVector = new FingerPrintAnimatedVector(this,
|
||||||
fingerprintImageView);
|
fingerprintImageView);
|
||||||
}
|
}
|
||||||
|
|
||||||
entrySelectionMode = EntrySelectionHelper.isIntentInEntrySelectionMode(getIntent());
|
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
||||||
autofillHelper = new AutofillHelper();
|
|
||||||
autofillHelper.retrieveAssistStructure(getIntent());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -974,20 +945,21 @@ public class PasswordActivity extends StylishActivity
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void launchGroupActivity() {
|
private void launchGroupActivity() {
|
||||||
AssistStructure assistStructure = null;
|
EntrySelectionHelper.INSTANCE.doEntrySelectionAction(getIntent(),
|
||||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
|
() -> {
|
||||||
assistStructure = autofillHelper.getAssistStructure();
|
GroupActivity.launch(PasswordActivity.this, readOnly);
|
||||||
if (assistStructure != null) {
|
return null;
|
||||||
|
},
|
||||||
|
() -> {
|
||||||
|
GroupActivity.launchForKeyboardSelection(PasswordActivity.this, readOnly);
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
assistStructure -> {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
GroupActivity.launchForAutofillResult(PasswordActivity.this, assistStructure, readOnly);
|
GroupActivity.launchForAutofillResult(PasswordActivity.this, assistStructure, readOnly);
|
||||||
}
|
}
|
||||||
}
|
return null;
|
||||||
if (assistStructure == null) {
|
});
|
||||||
if (entrySelectionMode) {
|
|
||||||
GroupActivity.launchForKeyboardResult(PasswordActivity.this, readOnly);
|
|
||||||
} else {
|
|
||||||
GroupActivity.launch(PasswordActivity.this, readOnly);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -1060,9 +1032,8 @@ public class PasswordActivity extends StylishActivity
|
|||||||
super.onActivityResult(requestCode, resultCode, data);
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
|
|
||||||
// To get entry in result
|
// To get entry in result
|
||||||
EntrySelectionHelper.onActivityResultSetResultAndFinish(this, requestCode, resultCode, data);
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
AutofillHelper.onActivityResultSetResultAndFinish(this, requestCode, resultCode, data);
|
AutofillHelper.INSTANCE.onActivityResultSetResultAndFinish(this, requestCode, resultCode, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean keyFileResult = false;
|
boolean keyFileResult = false;
|
||||||
|
|||||||
@@ -1,71 +0,0 @@
|
|||||||
package com.kunzisoft.keepass.selection;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import com.kunzisoft.keepass.database.PwEntry;
|
|
||||||
import com.kunzisoft.keepass.model.Entry;
|
|
||||||
import com.kunzisoft.keepass.model.Field;
|
|
||||||
|
|
||||||
public class EntrySelectionHelper {
|
|
||||||
|
|
||||||
public static final int ENTRY_SELECTION_RESPONSE_REQUEST_CODE = 5164;
|
|
||||||
|
|
||||||
public static final String EXTRA_ENTRY_SELECTION_MODE = "com.kunzisoft.keepass.extra.ENTRY_SELECTION_MODE";
|
|
||||||
|
|
||||||
public static void addEntrySelectionModeExtraInIntent(Intent intent) {
|
|
||||||
intent.putExtra(EXTRA_ENTRY_SELECTION_MODE, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isIntentInEntrySelectionMode(Intent intent) {
|
|
||||||
return intent.getBooleanExtra(EXTRA_ENTRY_SELECTION_MODE, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method to hit when right key is selected
|
|
||||||
*/
|
|
||||||
public static void buildResponseWhenEntrySelected(Activity activity, PwEntry entry) {
|
|
||||||
Intent mReplyIntent;
|
|
||||||
Intent intent = activity.getIntent();
|
|
||||||
boolean entrySelectionMode = isIntentInEntrySelectionMode(intent);
|
|
||||||
if (entrySelectionMode) {
|
|
||||||
mReplyIntent = new Intent();
|
|
||||||
|
|
||||||
Entry entryModel = new Entry();
|
|
||||||
entryModel.setTitle(entry.getTitle());
|
|
||||||
entryModel.setUsername(entry.getUsername());
|
|
||||||
entryModel.setPassword(entry.getPassword());
|
|
||||||
entryModel.setUrl(entry.getUrl());
|
|
||||||
if (entry.containsCustomFields()) {
|
|
||||||
entry.getFields()
|
|
||||||
.doActionToAllCustomProtectedField(
|
|
||||||
(key, value) -> entryModel.addCustomField(
|
|
||||||
new Field(key, value.toString())));
|
|
||||||
}
|
|
||||||
Log.d(activity.getClass().getName(), "Build entry selection for reply: " + entryModel.getTitle());
|
|
||||||
|
|
||||||
mReplyIntent.putExtra(
|
|
||||||
EXTRA_ENTRY_SELECTION_MODE,
|
|
||||||
entryModel);
|
|
||||||
activity.setResult(Activity.RESULT_OK, mReplyIntent);
|
|
||||||
} else {
|
|
||||||
activity.setResult(Activity.RESULT_CANCELED);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Utility method to loop and close each activity with return data
|
|
||||||
*/
|
|
||||||
public static void onActivityResultSetResultAndFinish(Activity activity, int requestCode, int resultCode, Intent data) {
|
|
||||||
if (requestCode == ENTRY_SELECTION_RESPONSE_REQUEST_CODE) {
|
|
||||||
if (resultCode == Activity.RESULT_OK) {
|
|
||||||
activity.setResult(resultCode, data);
|
|
||||||
}
|
|
||||||
if (resultCode == Activity.RESULT_CANCELED) {
|
|
||||||
activity.setResult(Activity.RESULT_CANCELED);
|
|
||||||
}
|
|
||||||
activity.finish();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package com.kunzisoft.keepass.selection
|
||||||
|
|
||||||
|
import android.app.assist.AssistStructure
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Build
|
||||||
|
import com.kunzisoft.keepass.autofill.AutofillHelper
|
||||||
|
|
||||||
|
object EntrySelectionHelper {
|
||||||
|
|
||||||
|
private const val EXTRA_ENTRY_SELECTION_MODE = "com.kunzisoft.keepass.extra.ENTRY_SELECTION_MODE"
|
||||||
|
|
||||||
|
fun addEntrySelectionModeExtraInIntent(intent: Intent) {
|
||||||
|
intent.putExtra(EXTRA_ENTRY_SELECTION_MODE, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun doEntrySelectionAction(intent: Intent,
|
||||||
|
standardAction: () -> Unit,
|
||||||
|
keyboardAction: () -> Unit,
|
||||||
|
autofillAction: (assistStructure: AssistStructure) -> Unit) {
|
||||||
|
var assistStructure: AssistStructure? = null
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
assistStructure = AutofillHelper.retrieveAssistStructure(intent)
|
||||||
|
assistStructure?.let {
|
||||||
|
autofillAction.invoke(assistStructure)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (assistStructure == null) {
|
||||||
|
if (intent.getBooleanExtra(EXTRA_ENTRY_SELECTION_MODE, false)) {
|
||||||
|
intent.putExtra(EXTRA_ENTRY_SELECTION_MODE, false)
|
||||||
|
keyboardAction.invoke()
|
||||||
|
} else {
|
||||||
|
standardAction.invoke()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
package com.kunzisoft.keepass.selection
|
|
||||||
|
|
||||||
import android.app.Activity
|
|
||||||
import android.content.Intent
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.preference.PreferenceManager
|
|
||||||
import android.support.v7.app.AppCompatActivity
|
|
||||||
import android.util.Log
|
|
||||||
import com.kunzisoft.keepass.R
|
|
||||||
import com.kunzisoft.keepass.activities.GroupActivity
|
|
||||||
import com.kunzisoft.keepass.app.App
|
|
||||||
import com.kunzisoft.keepass.fileselect.FileSelectActivity
|
|
||||||
import com.kunzisoft.keepass.magikeyboard.KeyboardEntryNotificationService
|
|
||||||
import com.kunzisoft.keepass.magikeyboard.MagikIME
|
|
||||||
import com.kunzisoft.keepass.model.Entry
|
|
||||||
import com.kunzisoft.keepass.selection.EntrySelectionHelper.ENTRY_SELECTION_RESPONSE_REQUEST_CODE
|
|
||||||
import com.kunzisoft.keepass.selection.EntrySelectionHelper.EXTRA_ENTRY_SELECTION_MODE
|
|
||||||
import com.kunzisoft.keepass.timeout.TimeoutHelper
|
|
||||||
|
|
||||||
class KeyboardEntryRetrieverActivity : AppCompatActivity() {
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
|
|
||||||
val TAG = KeyboardEntryRetrieverActivity::class.java.name!!
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
TimeoutHelper.checkTime(this) {}
|
|
||||||
if (App.getDB().loaded)
|
|
||||||
GroupActivity.launchForKeyboardResult(this, true)
|
|
||||||
else {
|
|
||||||
// Pass extra to get entry
|
|
||||||
FileSelectActivity.launchForKeyboardResult(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
|
||||||
super.onActivityResult(requestCode, resultCode, data)
|
|
||||||
Log.d(TAG, "Retrieve the entry selected, requestCode: $requestCode, resultCode: $resultCode")
|
|
||||||
if (requestCode == ENTRY_SELECTION_RESPONSE_REQUEST_CODE) {
|
|
||||||
if (resultCode == Activity.RESULT_OK) {
|
|
||||||
val entry = data?.getParcelableExtra<Entry>(EXTRA_ENTRY_SELECTION_MODE)
|
|
||||||
Log.d(TAG, "Set the entry ${entry?.title} to keyboard")
|
|
||||||
MagikIME.setEntryKey(entry)
|
|
||||||
|
|
||||||
// Show the notification if allowed in Preferences
|
|
||||||
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
|
|
||||||
if (sharedPreferences.getBoolean(getString(R.string.keyboard_notification_entry_key),
|
|
||||||
resources.getBoolean(R.bool.keyboard_notification_entry_default))) {
|
|
||||||
val notificationIntent = Intent(this, KeyboardEntryNotificationService::class.java)
|
|
||||||
startService(notificationIntent)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (resultCode == Activity.RESULT_CANCELED) {
|
|
||||||
Log.w(TAG, "Entry not retrieved")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -197,6 +197,12 @@ public class PreferencesUtil {
|
|||||||
context.getResources().getBoolean(R.bool.enable_read_only_default));
|
context.getResources().getBoolean(R.bool.enable_read_only_default));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean enableKeyboardNotificationEntry(Context context) {
|
||||||
|
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
|
return prefs.getBoolean(context.getString(R.string.keyboard_notification_entry_key),
|
||||||
|
context.getResources().getBoolean(R.bool.keyboard_notification_entry_default));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All preference keys associated with education
|
* All preference keys associated with education
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ open class SettingsActivity : LockingActivity(), MainPreferenceFragment.Callback
|
|||||||
intent.putExtra(TIMEOUT_ENABLE_KEY, timeoutEnable)
|
intent.putExtra(TIMEOUT_ENABLE_KEY, timeoutEnable)
|
||||||
if (!timeoutEnable) {
|
if (!timeoutEnable) {
|
||||||
activity.startActivity(intent)
|
activity.startActivity(intent)
|
||||||
} else if (TimeoutHelper.checkTime(activity)) {
|
} else if (TimeoutHelper.checkTimeAndLockIfTimeout(activity)) {
|
||||||
activity.startActivity(intent)
|
activity.startActivity(intent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,9 +78,10 @@ object TimeoutHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check the time previously record with recordTime and do the shutdown action if timeout
|
* Check the time previously record with recordTime and do the [timeoutAction] if timeout
|
||||||
|
* return 'false' if timeout, 'true' if in time
|
||||||
*/
|
*/
|
||||||
fun checkTime(context: Context, shutdown: (() -> Unit)): Boolean {
|
fun checkTime(context: Context, timeoutAction: (() -> Unit)? = null): Boolean {
|
||||||
// Cancel the lock PendingIntent
|
// Cancel the lock PendingIntent
|
||||||
if (App.getDB().loaded) {
|
if (App.getDB().loaded) {
|
||||||
val am = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
|
val am = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
|
||||||
@@ -118,7 +119,7 @@ object TimeoutHelper {
|
|||||||
if (diff >= appTimeout) {
|
if (diff >= appTimeout) {
|
||||||
// We have timed out
|
// We have timed out
|
||||||
App.getDB().loaded = false
|
App.getDB().loaded = false
|
||||||
shutdown.invoke()
|
timeoutAction?.invoke()
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
@@ -127,14 +128,14 @@ object TimeoutHelper {
|
|||||||
/**
|
/**
|
||||||
* Check the time previously record with recordTime and lock the activity if timeout
|
* Check the time previously record with recordTime and lock the activity if timeout
|
||||||
*/
|
*/
|
||||||
fun checkTime(activity: Activity): Boolean {
|
fun checkTimeAndLockIfTimeout(activity: Activity): Boolean {
|
||||||
return checkTime(activity) {
|
return checkTime(activity) {
|
||||||
activity.lock()
|
activity.lock()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun lockOrResetTimeout(activity: Activity, action: (() -> Unit)? = null) {
|
fun lockOrResetTimeout(activity: Activity, action: (() -> Unit)? = null) {
|
||||||
if (checkTime(activity)) {
|
if (checkTimeAndLockIfTimeout(activity)) {
|
||||||
recordTime(activity)
|
recordTime(activity)
|
||||||
action?.invoke()
|
action?.invoke()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user