Refactor Autofill and Keyboard selection

This commit is contained in:
J-Jamet
2019-02-22 13:34:07 +01:00
parent ff7f0e0a60
commit da86a971b5
21 changed files with 441 additions and 559 deletions

View File

@@ -126,10 +126,10 @@
android:configChanges="orientation|keyboardHidden"
android:windowSoftInputMode="stateHidden" />
<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" />
<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">
</activity>
<activity android:name="com.kunzisoft.keepass.settings.MagikIMESettings"

View File

@@ -86,7 +86,7 @@ public class EntryActivity extends LockingHideActivity {
private int iconColor;
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.putExtra(KEY_ENTRY, Types.UUIDtoBytes(pw.getUUID()));
ReadOnlyHelper.putReadOnlyInIntent(intent, readOnly);

View File

@@ -117,7 +117,7 @@ public class EntryEditActivity extends LockingHideActivity
* @param pwEntry Entry to update
*/
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.putExtra(KEY_ENTRY, Types.UUIDtoBytes(pwEntry.getUUID()));
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
*/
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.putExtra(KEY_PARENT, pwGroup.getId());
activity.startActivityForResult(intent, ADD_OR_UPDATE_ENTRY_REQUEST_CODE);

View File

@@ -35,6 +35,7 @@ import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
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.ReadOnlyDialog;
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.selection.EntrySelectionHelper;
import com.kunzisoft.keepass.settings.PreferencesUtil;
@@ -132,16 +136,13 @@ public class GroupActivity extends LockingActivity
private PwNode nodeToCopy;
private PwNode nodeToMove;
private boolean entrySelectionMode;
private AutofillHelper autofillHelper;
private SearchEntryCursorAdapter searchSuggestionAdapter;
private int iconColor;
private static void buildAndLaunchIntent(Activity activity, PwGroup group, boolean readOnly,
IntentBuildLauncher intentBuildLauncher) {
if (TimeoutHelper.INSTANCE.checkTime(activity)) {
if (TimeoutHelper.INSTANCE.checkTimeAndLockIfTimeout(activity)) {
Intent intent = new Intent(activity, GroupActivity.class);
if (group != null) {
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 act) {
launch(act, READ_ONLY_DEFAULT);
public static void launch(Activity activity) {
launch(activity, READ_ONLY_DEFAULT);
}
public static void launch(Activity act, boolean readOnly) {
TimeoutHelper.INSTANCE.recordTime(act);
launch(act, null, readOnly);
public static void launch(Activity activity, boolean readOnly) {
launch(activity, null, readOnly);
}
public static void launch(Activity activity, PwGroup group, boolean readOnly) {
TimeoutHelper.INSTANCE.recordTime(activity);
buildAndLaunchIntent(activity, group, readOnly,
(intent) -> activity.startActivityForResult(intent, 0));
}
@@ -179,16 +179,15 @@ public class GroupActivity extends LockingActivity
* -------------------------
*/
public static void launchForKeyboardResult(Activity activity, boolean readOnly) {
TimeoutHelper.INSTANCE.recordTime(activity);
launchForKeyboardResult(activity, null, readOnly);
public static void launchForKeyboardSelection(Activity activity, boolean readOnly) {
launchForKeyboardSelection(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
TimeoutHelper.INSTANCE.recordTime(activity);
buildAndLaunchIntent(activity, group, readOnly, (intent) -> {
EntrySelectionHelper.addEntrySelectionModeExtraInIntent(intent);
activity.startActivityForResult(intent, EntrySelectionHelper.ENTRY_SELECTION_RESPONSE_REQUEST_CODE);
KeyboardHelper.INSTANCE.startActivityForKeyboardSelection(activity, intent);
});
}
@@ -199,26 +198,17 @@ public class GroupActivity extends LockingActivity
*/
@RequiresApi(api = Build.VERSION_CODES.O)
public static void launchForAutofillResult(Activity activity, AssistStructure assistStructure, boolean readOnly) {
if ( assistStructure != null ) {
TimeoutHelper.INSTANCE.recordTime(activity);
public static void launchForAutofillResult(Activity activity, @NonNull AssistStructure assistStructure, boolean readOnly) {
launchForAutofillResult(activity, null, assistStructure, readOnly);
} else {
launch(activity, readOnly);
}
}
@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
if ( assistStructure != null ) {
TimeoutHelper.INSTANCE.recordTime(activity);
buildAndLaunchIntent(activity, group, readOnly, (intent) -> {
AutofillHelper.addAssistStructureExtraInIntent(intent, assistStructure);
activity.startActivityForResult(intent, AutofillHelper.AUTOFILL_RESPONSE_REQUEST_CODE);
AutofillHelper.INSTANCE.startActivityForAutofillResult(activity, intent, assistStructure);
});
} else {
launch(activity, group, readOnly);
}
}
@Override
@@ -316,13 +306,6 @@ public class GroupActivity extends LockingActivity
addNodeButtonView.setAddEntryClickListener(v ->
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
searchSuggestionAdapter = new SearchEntryCursorAdapter(this, database);
@@ -507,47 +490,46 @@ public class GroupActivity extends LockingActivity
@Override
public void onNodeClick(PwNode node) {
// Add event when we have Autofill
AssistStructure assistStructure = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
assistStructure = autofillHelper.getAssistStructure();
if (assistStructure != null) {
switch (node.getType()) {
case GROUP:
try {
openChildGroup((PwGroup) node);
} catch (ClassCastException e) {
Log.e(TAG, "Node can't be cast in Group");
}
break;
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
autofillHelper.buildResponseWhenEntrySelected(this, (PwEntry) node);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
AutofillHelper.INSTANCE.buildResponseWhenEntrySelected(GroupActivity.this, entry);
}
finish();
return null;
});
} catch (ClassCastException e) {
Log.e(TAG, "Node can't be cast in Entry");
}
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
public boolean onOpenMenuClick(PwNode node) {
@@ -920,7 +902,6 @@ public class GroupActivity extends LockingActivity
@Override
public void startActivity(Intent intent) {
boolean customSearchQueryExecuted = false;
// Get the intent, verify the action and get the query
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
@@ -931,22 +912,26 @@ public class GroupActivity extends LockingActivity
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;
EntrySelectionHelper.INSTANCE.doEntrySelectionAction(intent,
() -> {
GroupActivity.super.startActivity(intent);
return null;
},
() -> {
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
else if (EntrySelectionHelper.isIntentInEntrySelectionMode(getIntent())){
EntrySelectionHelper.addEntrySelectionModeExtraInIntent(searchIntent);
startActivityForResult(searchIntent, EntrySelectionHelper.ENTRY_SELECTION_RESPONSE_REQUEST_CODE);
customSearchQueryExecuted = true;
}
}
if (!customSearchQueryExecuted) {
super.startActivity(intent);
return null;
});
}
}
@@ -1179,9 +1164,8 @@ public class GroupActivity extends LockingActivity
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
EntrySelectionHelper.onActivityResultSetResultAndFinish(this, requestCode, resultCode, data);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
AutofillHelper.onActivityResultSetResultAndFinish(this, requestCode, resultCode, data);
AutofillHelper.INSTANCE.onActivityResultSetResultAndFinish(this, requestCode, resultCode, data);
}
}

View File

@@ -103,7 +103,7 @@ abstract class LockingActivity : StylishActivity() {
// After the first creation
// or If simply swipe with another application
// If the time is out -> close the Activity
TimeoutHelper.checkTime(this)
TimeoutHelper.checkTimeAndLockIfTimeout(this)
// If onCreate already record time
if (!exitLock)
TimeoutHelper.recordTime(this)
@@ -121,7 +121,7 @@ abstract class LockingActivity : StylishActivity() {
if (timeoutEnable) {
// If the time is out during our navigation in activity -> close the Activity
TimeoutHelper.checkTime(this)
TimeoutHelper.checkTimeAndLockIfTimeout(this)
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2017 Jeremy Jamet / Kunzisoft.
* Copyright 2019 Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePass DX.
*
@@ -34,12 +34,12 @@ import com.kunzisoft.keepass.fileselect.FileSelectActivity
import com.kunzisoft.keepass.timeout.TimeoutHelper
@RequiresApi(api = Build.VERSION_CODES.O)
class AutoFillAuthActivity : AppCompatActivity() {
class AutoFillLauncherActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
TimeoutHelper.checkTime(this) {}
// Pass extra for Autofill (EXTRA_ASSIST_STRUCTURE)
val assistStructure = AutofillHelper().retrieveAssistStructure(intent)
TimeoutHelper.checkTime(this)
val assistStructure = AutofillHelper.retrieveAssistStructure(intent)
if (assistStructure != null) {
if (App.getDB().loaded)
GroupActivity.launchForAutofillResult(this, assistStructure, true)
@@ -54,14 +54,14 @@ class AutoFillAuthActivity : AppCompatActivity() {
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)
}
companion object {
fun getAuthIntentSenderForResponse(context: Context): IntentSender {
val intent = Intent(context, AutoFillAuthActivity::class.java)
val intent = Intent(context, AutoFillLauncherActivity::class.java)
return PendingIntent.getActivity(context, 0,
intent, PendingIntent.FLAG_CANCEL_CURRENT).intentSender
}

View File

@@ -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;
}
}

View File

@@ -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
}
}

View File

@@ -62,7 +62,7 @@ public class KeeAutofillService extends AutofillService {
if (!Arrays.asList(autofillIds).isEmpty()) {
// If the entire Autofill Response is authenticated, AuthActivity is used
// 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);
responseBuilder.setAuthentication(autofillIds, sender, presentation);
callback.onSuccess(responseBuilder.build());

View File

@@ -23,6 +23,8 @@ import android.os.Parcel;
import com.kunzisoft.keepass.database.iterator.EntrySearchStringIterator;
import com.kunzisoft.keepass.database.security.ProtectedString;
import com.kunzisoft.keepass.model.Entry;
import com.kunzisoft.keepass.model.Field;
import java.util.UUID;
@@ -199,6 +201,21 @@ public abstract class PwEntry<Parent extends PwGroup> extends PwNode<Parent> {
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
public boolean equals(Object o) {
if (this == o) return true;

View File

@@ -53,9 +53,9 @@ import com.kunzisoft.keepass.app.App;
import com.kunzisoft.keepass.autofill.AutofillHelper;
import com.kunzisoft.keepass.database.action.CreateDatabaseRunnable;
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.CreateFileDialogFragment;
import com.kunzisoft.keepass.magikeyboard.KeyboardHelper;
import com.kunzisoft.keepass.password.AssignPasswordHelper;
import com.kunzisoft.keepass.password.PasswordActivity;
import com.kunzisoft.keepass.selection.EntrySelectionHelper;
@@ -104,9 +104,6 @@ public class FileSelectActivity extends StylishActivity implements
// TODO Consultation Mode
private boolean consultationMode = false;
private boolean entrySelectionMode;
private AutofillHelper autofillHelper;
private View fileSelectExpandableButton;
private ExpandableLayout fileSelectExpandable;
private EditText openFileNameView;
@@ -118,27 +115,33 @@ public class FileSelectActivity extends StylishActivity implements
private String defaultPath;
public static void launch(Activity activity) {
Intent intent = new Intent(activity, FileSelectActivity.class);
// only to avoid visible flickering when redirecting
activity.startActivityForResult(intent, RESULT_CANCELED);
/*
* -------------------------
* No Standard Launch, pass by PasswordActivity
* -------------------------
*/
/*
* -------------------------
* 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);
activity.startActivityForResult(intent, EntrySelectionHelper.ENTRY_SELECTION_RESPONSE_REQUEST_CODE);
}
/*
* -------------------------
* Autofill Launch
* -------------------------
*/
@RequiresApi(api = Build.VERSION_CODES.O)
public static void launchForAutofillResult(Activity activity, AssistStructure assistStructure) {
if ( assistStructure != null ) {
Intent intent = new Intent(activity, FileSelectActivity.class);
AutofillHelper.addAssistStructureExtraInIntent(intent, assistStructure);
activity.startActivityForResult(intent, AutofillHelper.AUTOFILL_RESPONSE_REQUEST_CODE);
} else {
launch(activity);
}
public static void launchForAutofillResult(Activity activity, @NonNull AssistStructure assistStructure) {
AutofillHelper.INSTANCE.startActivityForAutofillResult(activity,
new Intent(activity, FileSelectActivity.class),
assistStructure);
}
@Override
@@ -177,13 +180,6 @@ public class FileSelectActivity extends StylishActivity implements
RecyclerView mListFiles = findViewById(R.id.file_list);
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
openButtonView = findViewById(R.id.open_database);
openButtonView.setOnClickListener(v -> {
@@ -243,40 +239,52 @@ public class FileSelectActivity extends StylishActivity implements
checkAndPerformedEducation();
}
private void launchPasswordActivityWithPath(String path) {
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) {
private void fileNoFoundAction(FileNotFoundException e) {
String error = getString(R.string.file_not_found_content);
Toast.makeText(FileSelectActivity.this,
error, Toast.LENGTH_LONG).show();
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() {
@@ -603,32 +611,7 @@ public class FileSelectActivity extends StylishActivity implements
@Override
public void onFileItemOpenListener(int itemPosition) {
new OpenFileHistoryAsyncTask((fileName, keyFile) -> {
// TODO ENCAPSULATE
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();
}
launchPasswordActivity(fileName, keyFile);
updateFileListVisibility();
}, fileHistory).execute(itemPosition);
}
@@ -656,10 +639,8 @@ public class FileSelectActivity extends StylishActivity implements
protected void onActivityResult(int requestCode, int resultCode, Intent 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) {
AutofillHelper.onActivityResultSetResultAndFinish(this, requestCode, resultCode, data);
AutofillHelper.INSTANCE.onActivityResultSetResultAndFinish(this, requestCode, resultCode, data);
}
keyFileHelper.onActivityResultCallback(requestCode, resultCode, data,

View File

@@ -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)
}
}

View File

@@ -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)
}
}

View File

@@ -48,7 +48,6 @@ import com.kunzisoft.keepass.magikeyboard.adapter.FieldsAdapter;
import com.kunzisoft.keepass.magikeyboard.receiver.LockBroadcastReceiver;
import com.kunzisoft.keepass.magikeyboard.view.MagikeyboardView;
import com.kunzisoft.keepass.model.Entry;
import com.kunzisoft.keepass.selection.KeyboardEntryRetrieverActivity;
import static com.kunzisoft.keepass.magikeyboard.receiver.LockBroadcastReceiver.LOCK_ACTION;
@@ -206,8 +205,7 @@ public class MagikIME extends InputMethodService
break;
case KEY_ENTRY:
deleteEntryKey(this);
Intent intent = new Intent(this, KeyboardEntryRetrieverActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Intent intent = new Intent(this, KeyboardLauncherActivity.class);
startActivity(intent);
break;
case KEY_LOCK:

View File

@@ -70,6 +70,7 @@ 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.magikeyboard.KeyboardHelper;
import com.kunzisoft.keepass.selection.EntrySelectionHelper;
import com.kunzisoft.keepass.settings.PreferencesUtil;
import com.kunzisoft.keepass.stylish.StylishActivity;
@@ -133,9 +134,6 @@ public class PasswordActivity extends StylishActivity
private KeyFileHelper keyFileHelper;
protected boolean entrySelectionMode;
private AutofillHelper autofillHelper;
private static void buildAndLaunchIntent(Activity activity, String fileName, String keyFile,
IntentBuildLauncher intentBuildLauncher) {
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(
Activity activity,
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(
Activity activity,
String fileName,
@@ -200,9 +186,7 @@ public class PasswordActivity extends StylishActivity
verifyFileNameUriFromLaunch(fileName);
buildAndLaunchIntent(activity, fileName, keyFile, (intent) -> {
EntrySelectionHelper.addEntrySelectionModeExtraInIntent(intent);
// only to avoid visible flickering when redirecting
activity.startActivityForResult(intent, EntrySelectionHelper.ENTRY_SELECTION_RESPONSE_REQUEST_CODE);
KeyboardHelper.INSTANCE.startActivityForKeyboardSelection(activity, intent);
});
}
@@ -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)
public static void launchForAutofillResult(
Activity activity,
@@ -230,8 +206,10 @@ public class PasswordActivity extends StylishActivity
if ( assistStructure != null ) {
buildAndLaunchIntent(activity, fileName, keyFile, (intent) -> {
AutofillHelper.addAssistStructureExtraInIntent(intent, assistStructure);
activity.startActivityForResult(intent, AutofillHelper.AUTOFILL_RESPONSE_REQUEST_CODE);
AutofillHelper.INSTANCE.startActivityForAutofillResult(
activity,
intent,
assistStructure);
});
} else {
launch(activity, fileName, keyFile);
@@ -310,13 +288,6 @@ public class PasswordActivity extends StylishActivity
fingerPrintAnimatedVector = new FingerPrintAnimatedVector(this,
fingerprintImageView);
}
entrySelectionMode = EntrySelectionHelper.isIntentInEntrySelectionMode(getIntent());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
autofillHelper = new AutofillHelper();
autofillHelper.retrieveAssistStructure(getIntent());
}
}
@Override
@@ -974,20 +945,21 @@ public class PasswordActivity extends StylishActivity
}
private void launchGroupActivity() {
AssistStructure assistStructure = null;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
assistStructure = autofillHelper.getAssistStructure();
if (assistStructure != null) {
EntrySelectionHelper.INSTANCE.doEntrySelectionAction(getIntent(),
() -> {
GroupActivity.launch(PasswordActivity.this, readOnly);
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);
}
}
if (assistStructure == null) {
if (entrySelectionMode) {
GroupActivity.launchForKeyboardResult(PasswordActivity.this, readOnly);
} else {
GroupActivity.launch(PasswordActivity.this, readOnly);
}
}
return null;
});
}
@Override
@@ -1060,9 +1032,8 @@ public class PasswordActivity extends StylishActivity
super.onActivityResult(requestCode, resultCode, data);
// To get entry in result
EntrySelectionHelper.onActivityResultSetResultAndFinish(this, requestCode, resultCode, data);
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;

View File

@@ -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();
}
}
}

View File

@@ -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()
}
}
}
}

View File

@@ -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()
}
}

View File

@@ -197,6 +197,12 @@ public class PreferencesUtil {
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
*/

View File

@@ -48,7 +48,7 @@ open class SettingsActivity : LockingActivity(), MainPreferenceFragment.Callback
intent.putExtra(TIMEOUT_ENABLE_KEY, timeoutEnable)
if (!timeoutEnable) {
activity.startActivity(intent)
} else if (TimeoutHelper.checkTime(activity)) {
} else if (TimeoutHelper.checkTimeAndLockIfTimeout(activity)) {
activity.startActivity(intent)
}
}

View File

@@ -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
if (App.getDB().loaded) {
val am = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
@@ -118,7 +119,7 @@ object TimeoutHelper {
if (diff >= appTimeout) {
// We have timed out
App.getDB().loaded = false
shutdown.invoke()
timeoutAction?.invoke()
return false
}
return true
@@ -127,14 +128,14 @@ object TimeoutHelper {
/**
* 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) {
activity.lock()
}
}
fun lockOrResetTimeout(activity: Activity, action: (() -> Unit)? = null) {
if (checkTime(activity)) {
if (checkTimeAndLockIfTimeout(activity)) {
recordTime(activity)
action?.invoke()
}