mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
Add autofill service and preference
This commit is contained in:
2
.idea/misc.xml
generated
2
.idea/misc.xml
generated
@@ -24,7 +24,7 @@
|
||||
</value>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||
</component>
|
||||
<component name="ProjectType">
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
android {
|
||||
compileSdkVersion = 25
|
||||
compileSdkVersion = 26
|
||||
buildToolsVersion = "26.0.2"
|
||||
|
||||
defaultConfig {
|
||||
applicationId "com.kunzisoft.keepass"
|
||||
minSdkVersion 14
|
||||
targetSdkVersion 25
|
||||
targetSdkVersion 26
|
||||
versionCode = 1
|
||||
versionName = "2.5.0.0beta1"
|
||||
|
||||
@@ -52,18 +52,24 @@ android {
|
||||
buildConfigField "boolean", "GOOGLE_PLAY_VERSION", "true"
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
targetCompatibility 1.8
|
||||
sourceCompatibility 1.8
|
||||
}
|
||||
}
|
||||
|
||||
def supportVersion = "25.4.0"
|
||||
def supportVersion = "26.1.0"
|
||||
def spongycastleVersion = "1.58.0.0"
|
||||
|
||||
dependencies {
|
||||
androidTestCompile files('libs/junit4.jar')
|
||||
compile "com.android.support:appcompat-v7:$supportVersion"
|
||||
compile "com.android.support:design:$supportVersion"
|
||||
compile "com.android.support:preference-v7:$supportVersion"
|
||||
compile "com.android.support:preference-v14:$supportVersion"
|
||||
compile "com.madgag.spongycastle:core:$spongycastleVersion"
|
||||
compile "com.madgag.spongycastle:prov:$spongycastleVersion"
|
||||
compile "joda-time:joda-time:2.9.9"
|
||||
androidTestImplementation files('libs/junit4.jar')
|
||||
implementation "com.android.support:appcompat-v7:$supportVersion"
|
||||
implementation "com.android.support:design:$supportVersion"
|
||||
implementation "com.android.support:preference-v7:$supportVersion"
|
||||
implementation "com.android.support:preference-v14:$supportVersion"
|
||||
implementation "com.madgag.spongycastle:core:$spongycastleVersion"
|
||||
implementation "com.madgag.spongycastle:prov:$spongycastleVersion"
|
||||
implementation "joda-time:joda-time:2.9.9"
|
||||
implementation group: 'com.google.code.gson', name: 'gson', version: '2.8.1'
|
||||
implementation group: 'com.google.guava', name: 'guava', version: '22.0-android'
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ public class SearchTest extends AndroidTestCase {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
|
||||
SharedPreferences.Editor editor = prefs.edit();
|
||||
|
||||
editor.putBoolean(ctx.getString(R.string.omitbackup_key), setting);
|
||||
editor.putBoolean(ctx.getString(R.string.settings_omitbackup_key), setting);
|
||||
editor.commit();
|
||||
|
||||
}
|
||||
|
||||
@@ -102,8 +102,26 @@
|
||||
<meta-data android:name="android.app.searchable" android:resource="@xml/searchable" />
|
||||
</activity>
|
||||
<activity android:name="com.keepassdroid.settings.SettingsActivity" />
|
||||
<activity android:name="com.keepassdroid.AutoFillAuthActivity"
|
||||
android:configChanges="orientation|keyboardHidden" />
|
||||
<activity
|
||||
android:name="com.keepassdroid.settings.SettingsAutofillActivity"
|
||||
android:exported="true">
|
||||
</activity>
|
||||
|
||||
<service android:name="com.keepassdroid.services.TimeoutService" />
|
||||
<service
|
||||
android:name="com.keepassdroid.autofill.KeeAutofillService"
|
||||
android:label="@string/autofill_service_name"
|
||||
android:permission="android.permission.BIND_AUTOFILL_SERVICE">
|
||||
<meta-data
|
||||
android:name="android.autofill"
|
||||
android:resource="@xml/dataset_service" />
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.service.autofill.AutofillService" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
<meta-data android:name="com.sec.android.support.multiwindow" android:value="true" />
|
||||
</application>
|
||||
</manifest>
|
||||
34
app/src/main/java/com/keepassdroid/AutoFillAuthActivity.java
Normal file
34
app/src/main/java/com/keepassdroid/AutoFillAuthActivity.java
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2017 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 2 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.keepassdroid;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentSender;
|
||||
|
||||
public class AutoFillAuthActivity extends PasswordActivity {
|
||||
|
||||
public static IntentSender getAuthIntentSenderForResponse(Context context) {
|
||||
final Intent intent = new Intent(context, PasswordActivity.class);
|
||||
return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT)
|
||||
.getIntentSender();
|
||||
}
|
||||
}
|
||||
@@ -124,7 +124,7 @@ public class EntryActivity extends LockCloseHideActivity {
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
mShowPassword = ! prefs.getBoolean(getString(R.string.maskpass_key), getResources().getBoolean(R.bool.maskpass_default));
|
||||
mShowPassword = ! prefs.getBoolean(getString(R.string.settings_maskpass_key), getResources().getBoolean(R.bool.settings_maskpass_default));
|
||||
|
||||
super.onCreate(savedInstanceState);
|
||||
setEntryView();
|
||||
@@ -428,7 +428,7 @@ public class EntryActivity extends LockCloseHideActivity {
|
||||
}
|
||||
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
String sClipClear = prefs.getString(getString(R.string.clipboard_timeout_key), getString(R.string.clipboard_timeout_default));
|
||||
String sClipClear = prefs.getString(getString(R.string.settings_clipboard_timeout_key), getString(R.string.clipboard_timeout_default));
|
||||
|
||||
long clipClearTime = Long.parseLong(sClipClear);
|
||||
|
||||
|
||||
@@ -247,7 +247,7 @@ public abstract class GroupActivity extends GroupBaseActivity
|
||||
if (App.getDB().readOnly) {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
|
||||
if (prefs.getBoolean(getString(R.string.show_read_only_warning), true)) {
|
||||
if (prefs.getBoolean(getString(R.string.settings_show_read_only_warning), true)) {
|
||||
Dialog dialog = new ReadOnlyDialog(this);
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
@@ -191,7 +191,7 @@ public abstract class GroupBaseActivity extends LockCloseListActivity {
|
||||
|
||||
// Will be null if onPrepareOptionsMenu is called before onCreate
|
||||
if (prefs != null) {
|
||||
sortByName = prefs.getBoolean(getString(R.string.sort_key), getResources().getBoolean(R.bool.sort_default));
|
||||
sortByName = prefs.getBoolean(getString(R.string.settings_sort_key), getResources().getBoolean(R.bool.settings_sort_default));
|
||||
}
|
||||
|
||||
int resId;
|
||||
@@ -245,8 +245,8 @@ public abstract class GroupBaseActivity extends LockCloseListActivity {
|
||||
|
||||
private void toggleSort() {
|
||||
// Toggle setting
|
||||
String sortKey = getString(R.string.sort_key);
|
||||
boolean sortByName = prefs.getBoolean(sortKey, getResources().getBoolean(R.bool.sort_default));
|
||||
String sortKey = getString(R.string.settings_sort_key);
|
||||
boolean sortByName = prefs.getBoolean(sortKey, getResources().getBoolean(R.bool.settings_sort_default));
|
||||
Editor editor = prefs.edit();
|
||||
editor.putBoolean(sortKey, ! sortByName);
|
||||
EditorCompat.apply(editor);
|
||||
|
||||
@@ -194,7 +194,7 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
|
||||
prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
prefsNoBackup = getSharedPreferences("nobackup", Context.MODE_PRIVATE);
|
||||
|
||||
mRememberKeyfile = prefs.getBoolean(getString(R.string.keyfile_key), getResources().getBoolean(R.bool.keyfile_default));
|
||||
mRememberKeyfile = prefs.getBoolean(getString(R.string.settings_keyfile_key), getResources().getBoolean(R.bool.settings_keyfile_default));
|
||||
setContentView(R.layout.password);
|
||||
|
||||
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
|
||||
|
||||
@@ -79,7 +79,7 @@ public class PwGroupListAdapter extends BaseAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
boolean sortLists = prefs.getBoolean(mAct.getString(R.string.sort_key), mAct.getResources().getBoolean(R.bool.sort_default));
|
||||
boolean sortLists = prefs.getBoolean(mAct.getString(R.string.settings_sort_key), mAct.getResources().getBoolean(R.bool.settings_sort_default));
|
||||
if ( sortLists ) {
|
||||
groupsForViewing = new ArrayList<PwGroup>(mGroup.childGroups);
|
||||
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.keepassdroid.autofill;
|
||||
|
||||
import android.app.assist.AssistStructure.ViewNode;
|
||||
import android.os.Build;
|
||||
import android.support.annotation.RequiresApi;
|
||||
import android.view.autofill.AutofillId;
|
||||
|
||||
/**
|
||||
* A stripped down version of a {@link ViewNode} that contains only autofill-relevant metadata. It
|
||||
* also contains a {@code mSaveType} flag that is calculated based on the {@link ViewNode}]'s
|
||||
* autofill hints.
|
||||
*/
|
||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||
public class AutofillFieldMetadata {
|
||||
private int mSaveType = 0;
|
||||
private String[] mAutofillHints;
|
||||
private AutofillId mAutofillId;
|
||||
private int mAutofillType;
|
||||
private CharSequence[] mAutofillOptions;
|
||||
private boolean mFocused;
|
||||
|
||||
public AutofillFieldMetadata(ViewNode view) {
|
||||
mAutofillId = view.getAutofillId();
|
||||
mAutofillType = view.getAutofillType();
|
||||
mAutofillOptions = view.getAutofillOptions();
|
||||
mFocused = view.isFocused();
|
||||
String[] hints = AutofillHints.filterForSupportedHints(view.getAutofillHints());
|
||||
if (hints != null) {
|
||||
AutofillHints.convertToStoredHintNames(hints);
|
||||
setHints(hints);
|
||||
}
|
||||
}
|
||||
|
||||
public String[] getHints() {
|
||||
return mAutofillHints;
|
||||
}
|
||||
|
||||
public void setHints(String[] hints) {
|
||||
mAutofillHints = hints;
|
||||
mSaveType = AutofillHints.getSaveTypeForHints(hints);
|
||||
}
|
||||
|
||||
public int getSaveType() {
|
||||
return mSaveType;
|
||||
}
|
||||
|
||||
public AutofillId getId() {
|
||||
return mAutofillId;
|
||||
}
|
||||
|
||||
public int getAutofillType() {
|
||||
return mAutofillType;
|
||||
}
|
||||
|
||||
/**
|
||||
* When the {@link ViewNode} is a list that the user needs to choose a string from (i.e. a
|
||||
* spinner), this is called to return the index of a specific item in the list.
|
||||
*/
|
||||
public int getAutofillOptionIndex(String value) {
|
||||
for (int i = 0; i < mAutofillOptions.length; i++) {
|
||||
if (mAutofillOptions[i].toString().equals(value)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public boolean isFocused() {
|
||||
return mFocused;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.keepassdroid.autofill;
|
||||
|
||||
import android.view.autofill.AutofillId;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Data structure that stores a collection of {@code AutofillFieldMetadata}s. Contains all of the
|
||||
* client's {@code View} hierarchy autofill-relevant metadata.
|
||||
*/
|
||||
public final class AutofillFieldMetadataCollection {
|
||||
|
||||
private final List<AutofillId> mAutofillIds = new ArrayList<>();
|
||||
private final HashMap<String, List<AutofillFieldMetadata>> mAutofillHintsToFieldsMap = new HashMap<>();
|
||||
private final List<String> mAllAutofillHints = new ArrayList<>();
|
||||
private final List<String> mFocusedAutofillHints = new ArrayList<>();
|
||||
private int mSize = 0;
|
||||
private int mSaveType = 0;
|
||||
|
||||
public void add(AutofillFieldMetadata autofillFieldMetadata) {
|
||||
mSaveType |= autofillFieldMetadata.getSaveType();
|
||||
mSize++;
|
||||
mAutofillIds.add(autofillFieldMetadata.getId());
|
||||
List<String> hintsList = Arrays.asList(autofillFieldMetadata.getHints());
|
||||
mAllAutofillHints.addAll(hintsList);
|
||||
if (autofillFieldMetadata.isFocused()) {
|
||||
mFocusedAutofillHints.addAll(hintsList);
|
||||
}
|
||||
for (String hint : autofillFieldMetadata.getHints()) {
|
||||
if (!mAutofillHintsToFieldsMap.containsKey(hint)) {
|
||||
mAutofillHintsToFieldsMap.put(hint, new ArrayList<>());
|
||||
}
|
||||
mAutofillHintsToFieldsMap.get(hint).add(autofillFieldMetadata);
|
||||
}
|
||||
}
|
||||
|
||||
public int getSaveType() {
|
||||
return mSaveType;
|
||||
}
|
||||
|
||||
public AutofillId[] getAutofillIds() {
|
||||
return mAutofillIds.toArray(new AutofillId[mSize]);
|
||||
}
|
||||
|
||||
public List<AutofillFieldMetadata> getFieldsForHint(String hint) {
|
||||
return mAutofillHintsToFieldsMap.get(hint);
|
||||
}
|
||||
|
||||
public List<String> getFocusedHints() {
|
||||
return mFocusedAutofillHints;
|
||||
}
|
||||
|
||||
public List<String> getAllHints() {
|
||||
return mAllAutofillHints;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.keepassdroid.autofill;
|
||||
|
||||
import com.keepassdroid.model.FilledAutofillField;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Holds the properties associated with an autofill hint in this Autofill Service.
|
||||
*/
|
||||
public final class AutofillHintProperties {
|
||||
|
||||
private String mAutofillHint;
|
||||
private FakeFieldGenerator mFakeFieldGenerator;
|
||||
private Set<Integer> mValidTypes;
|
||||
private int mSaveType;
|
||||
private int mPartition;
|
||||
|
||||
// TODO Change to real field generator
|
||||
|
||||
public AutofillHintProperties(String autofillHint, int saveType, int partitionNumber,
|
||||
FakeFieldGenerator fakeFieldGenerator, Integer... validTypes) {
|
||||
mAutofillHint = autofillHint;
|
||||
mSaveType = saveType;
|
||||
mPartition = partitionNumber;
|
||||
mFakeFieldGenerator = fakeFieldGenerator;
|
||||
mValidTypes = new HashSet<>(Arrays.asList(validTypes));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates dummy autofill field data that is relevant to the autofill hint.
|
||||
*/
|
||||
public FilledAutofillField generateFakeField(int seed) {
|
||||
return mFakeFieldGenerator.generate(seed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns autofill hint associated with these properties. If you save a field that uses a W3C
|
||||
* hint, there is a chance this will return a different but analogous hint, when applicable.
|
||||
* For example, W3C has hint 'email' and {@link android.view.View} has hint 'emailAddress', so
|
||||
* the W3C hint should map to the hint defined in {@link android.view.View} ('emailAddress').
|
||||
*/
|
||||
public String getAutofillHint() {
|
||||
return mAutofillHint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns how this hint maps to a {@link android.service.autofill.SaveInfo} type.
|
||||
*/
|
||||
public int getSaveType() {
|
||||
return mSaveType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns which data partition this autofill hint should be a part of. See partitions defined
|
||||
* in {@link AutofillHints}.
|
||||
*/
|
||||
public int getPartition() {
|
||||
return mPartition;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sometimes, data for a hint should only be stored as a certain AutofillValue type. For
|
||||
* example, it is recommended that data representing a Credit Card Expiration date, annotated
|
||||
* with the hint {@link android.view.View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE}, should
|
||||
* only be stored as {@link android.view.View.AUTOFILL_TYPE_DATE}.
|
||||
*/
|
||||
public boolean isValidType(int type) {
|
||||
return mValidTypes.contains(type);
|
||||
}
|
||||
}
|
||||
775
app/src/main/java/com/keepassdroid/autofill/AutofillHints.java
Normal file
775
app/src/main/java/com/keepassdroid/autofill/AutofillHints.java
Normal file
@@ -0,0 +1,775 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.keepassdroid.autofill;
|
||||
|
||||
import android.os.Build;
|
||||
import android.service.autofill.SaveInfo;
|
||||
import android.support.annotation.RequiresApi;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.keepassdroid.model.FilledAutofillField;
|
||||
import com.keepassdroid.model.FilledAutofillFieldCollection;
|
||||
|
||||
import java.util.Calendar;
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||
public final class AutofillHints {
|
||||
public static final int PARTITION_OTHER = 0;
|
||||
public static final int PARTITION_ADDRESS = 1;
|
||||
public static final int PARTITION_EMAIL = 2;
|
||||
public static final int PARTITION_CREDIT_CARD = 3;
|
||||
public static final int[] PARTITIONS = {
|
||||
PARTITION_OTHER, PARTITION_ADDRESS, PARTITION_EMAIL, PARTITION_CREDIT_CARD
|
||||
};
|
||||
/* TODO: finish building fake data for all hints. */
|
||||
private static final ImmutableMap<String, AutofillHintProperties> sValidHints =
|
||||
new ImmutableMap.Builder<String, AutofillHintProperties>()
|
||||
.put(View.AUTOFILL_HINT_EMAIL_ADDRESS, new AutofillHintProperties(
|
||||
View.AUTOFILL_HINT_EMAIL_ADDRESS, SaveInfo.SAVE_DATA_TYPE_EMAIL_ADDRESS,
|
||||
PARTITION_EMAIL,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField =
|
||||
new FilledAutofillField(View.AUTOFILL_HINT_EMAIL_ADDRESS);
|
||||
filledAutofillField.setTextValue("email" + seed);
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
|
||||
.put(View.AUTOFILL_HINT_NAME, new AutofillHintProperties(
|
||||
View.AUTOFILL_HINT_NAME, SaveInfo.SAVE_DATA_TYPE_GENERIC,
|
||||
PARTITION_OTHER,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField =
|
||||
new FilledAutofillField(View.AUTOFILL_HINT_NAME);
|
||||
filledAutofillField.setTextValue("name" + seed);
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
|
||||
.put(View.AUTOFILL_HINT_USERNAME, new AutofillHintProperties(
|
||||
View.AUTOFILL_HINT_USERNAME, SaveInfo.SAVE_DATA_TYPE_USERNAME,
|
||||
PARTITION_OTHER,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField =
|
||||
new FilledAutofillField(View.AUTOFILL_HINT_USERNAME);
|
||||
filledAutofillField.setTextValue("login" + seed);
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
|
||||
.put(View.AUTOFILL_HINT_PASSWORD, new AutofillHintProperties(
|
||||
View.AUTOFILL_HINT_PASSWORD, SaveInfo.SAVE_DATA_TYPE_PASSWORD,
|
||||
PARTITION_OTHER,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField =
|
||||
new FilledAutofillField(View.AUTOFILL_HINT_PASSWORD);
|
||||
filledAutofillField.setTextValue("login" + seed);
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT))
|
||||
.put(View.AUTOFILL_HINT_PHONE, new AutofillHintProperties(
|
||||
View.AUTOFILL_HINT_PHONE, SaveInfo.SAVE_DATA_TYPE_GENERIC,
|
||||
PARTITION_OTHER,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField =
|
||||
new FilledAutofillField(View.AUTOFILL_HINT_PHONE);
|
||||
filledAutofillField.setTextValue("" + seed + "2345678910");
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
|
||||
.put(View.AUTOFILL_HINT_POSTAL_ADDRESS, new AutofillHintProperties(
|
||||
View.AUTOFILL_HINT_POSTAL_ADDRESS, SaveInfo.SAVE_DATA_TYPE_ADDRESS,
|
||||
PARTITION_ADDRESS,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField =
|
||||
new FilledAutofillField(View.AUTOFILL_HINT_POSTAL_ADDRESS);
|
||||
filledAutofillField.setTextValue(
|
||||
"" + seed + " Fake Ln, Fake, FA, FAA 10001");
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
|
||||
.put(View.AUTOFILL_HINT_POSTAL_CODE, new AutofillHintProperties(
|
||||
View.AUTOFILL_HINT_POSTAL_CODE, SaveInfo.SAVE_DATA_TYPE_ADDRESS,
|
||||
PARTITION_ADDRESS,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField =
|
||||
new FilledAutofillField(View.AUTOFILL_HINT_POSTAL_CODE);
|
||||
filledAutofillField.setTextValue("1000" + seed);
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
|
||||
.put(View.AUTOFILL_HINT_CREDIT_CARD_NUMBER, new AutofillHintProperties(
|
||||
View.AUTOFILL_HINT_CREDIT_CARD_NUMBER,
|
||||
SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD,
|
||||
PARTITION_CREDIT_CARD,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField = new FilledAutofillField(
|
||||
View.AUTOFILL_HINT_CREDIT_CARD_NUMBER);
|
||||
filledAutofillField.setTextValue("" + seed + "234567");
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT))
|
||||
.put(View.AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE, new AutofillHintProperties(
|
||||
View.AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE,
|
||||
SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD,
|
||||
PARTITION_CREDIT_CARD,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField = new FilledAutofillField(
|
||||
View.AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE);
|
||||
filledAutofillField.setTextValue("" + seed + seed + seed);
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT))
|
||||
.put(View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE,
|
||||
new AutofillHintProperties(
|
||||
View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE,
|
||||
SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD, PARTITION_CREDIT_CARD,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField = new FilledAutofillField(
|
||||
View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE);
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.set(Calendar.YEAR, calendar.get(Calendar.YEAR) + seed);
|
||||
filledAutofillField.setDateValue(calendar.getTimeInMillis());
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_DATE))
|
||||
.put(View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH,
|
||||
new AutofillHintProperties(
|
||||
View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH,
|
||||
SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD, PARTITION_CREDIT_CARD,
|
||||
(seed) -> {
|
||||
CharSequence[] months = monthRange();
|
||||
int month = seed % months.length;
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.set(Calendar.MONTH, month);
|
||||
FilledAutofillField filledAutofillField =
|
||||
new FilledAutofillField(
|
||||
View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH);
|
||||
filledAutofillField.setListValue(months, month);
|
||||
filledAutofillField.setTextValue(Integer.toString(month));
|
||||
filledAutofillField.setDateValue(calendar.getTimeInMillis());
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST,
|
||||
View.AUTOFILL_TYPE_DATE))
|
||||
.put(View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR, new AutofillHintProperties(
|
||||
View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR,
|
||||
SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD, PARTITION_CREDIT_CARD,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField = new FilledAutofillField(
|
||||
View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR);
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
int expYear = calendar.get(Calendar.YEAR) + seed;
|
||||
calendar.set(Calendar.YEAR, expYear);
|
||||
filledAutofillField.setDateValue(calendar.getTimeInMillis());
|
||||
filledAutofillField.setTextValue(Integer.toString(expYear));
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST,
|
||||
View.AUTOFILL_TYPE_DATE))
|
||||
.put(View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY, new AutofillHintProperties(
|
||||
View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY,
|
||||
SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD, PARTITION_CREDIT_CARD,
|
||||
(seed) -> {
|
||||
CharSequence[] days = dayRange();
|
||||
int day = seed % days.length;
|
||||
FilledAutofillField filledAutofillField = new FilledAutofillField(
|
||||
View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY);
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.set(Calendar.DATE, day);
|
||||
filledAutofillField.setListValue(days, day);
|
||||
filledAutofillField.setTextValue(Integer.toString(day));
|
||||
filledAutofillField.setDateValue(calendar.getTimeInMillis());
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST,
|
||||
View.AUTOFILL_TYPE_DATE))
|
||||
.put(W3cHints.HONORIFIC_PREFIX, new AutofillHintProperties(
|
||||
W3cHints.HONORIFIC_PREFIX, SaveInfo.SAVE_DATA_TYPE_GENERIC,
|
||||
PARTITION_OTHER,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField = new FilledAutofillField(
|
||||
W3cHints.HONORIFIC_PREFIX);
|
||||
CharSequence[] examplePrefixes = {"Miss", "Ms.", "Mr.", "Mx.",
|
||||
"Sr.", "Dr.", "Lady", "Lord"};
|
||||
filledAutofillField.setListValue(examplePrefixes,
|
||||
seed % examplePrefixes.length);
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
|
||||
.put(W3cHints.GIVEN_NAME, new AutofillHintProperties(W3cHints.GIVEN_NAME,
|
||||
SaveInfo.SAVE_DATA_TYPE_GENERIC,
|
||||
PARTITION_OTHER,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField =
|
||||
new FilledAutofillField(W3cHints.GIVEN_NAME);
|
||||
filledAutofillField.setTextValue("name" + seed);
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT))
|
||||
.put(W3cHints.ADDITIONAL_NAME, new AutofillHintProperties(
|
||||
W3cHints.ADDITIONAL_NAME, SaveInfo.SAVE_DATA_TYPE_GENERIC,
|
||||
PARTITION_OTHER,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField =
|
||||
new FilledAutofillField(W3cHints.ADDITIONAL_NAME);
|
||||
filledAutofillField.setTextValue("addtlname" + seed);
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT))
|
||||
.put(W3cHints.FAMILY_NAME, new AutofillHintProperties(
|
||||
W3cHints.FAMILY_NAME, SaveInfo.SAVE_DATA_TYPE_GENERIC,
|
||||
PARTITION_OTHER,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField =
|
||||
new FilledAutofillField(W3cHints.FAMILY_NAME);
|
||||
filledAutofillField.setTextValue("famname" + seed);
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT))
|
||||
.put(W3cHints.HONORIFIC_SUFFIX, new AutofillHintProperties(
|
||||
W3cHints.HONORIFIC_SUFFIX, SaveInfo.SAVE_DATA_TYPE_GENERIC,
|
||||
PARTITION_OTHER,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField =
|
||||
new FilledAutofillField(W3cHints.HONORIFIC_SUFFIX);
|
||||
CharSequence[] exampleSuffixes = {"san", "kun", "chan", "sama"};
|
||||
filledAutofillField.setListValue(exampleSuffixes,
|
||||
seed % exampleSuffixes.length);
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
|
||||
.put(W3cHints.NEW_PASSWORD, new AutofillHintProperties(
|
||||
W3cHints.NEW_PASSWORD, SaveInfo.SAVE_DATA_TYPE_PASSWORD,
|
||||
PARTITION_OTHER,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField =
|
||||
new FilledAutofillField(W3cHints.NEW_PASSWORD);
|
||||
filledAutofillField.setTextValue("login" + seed);
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT))
|
||||
.put(W3cHints.CURRENT_PASSWORD, new AutofillHintProperties(
|
||||
View.AUTOFILL_HINT_PASSWORD, SaveInfo.SAVE_DATA_TYPE_PASSWORD,
|
||||
PARTITION_OTHER,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField =
|
||||
new FilledAutofillField(View.AUTOFILL_HINT_PASSWORD);
|
||||
filledAutofillField.setTextValue("login" + seed);
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT))
|
||||
.put(W3cHints.ORGANIZATION_TITLE, new AutofillHintProperties(
|
||||
W3cHints.ORGANIZATION_TITLE, SaveInfo.SAVE_DATA_TYPE_GENERIC,
|
||||
PARTITION_OTHER,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField =
|
||||
new FilledAutofillField(W3cHints.ORGANIZATION_TITLE);
|
||||
filledAutofillField.setTextValue("org" + seed);
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
|
||||
.put(W3cHints.ORGANIZATION, new AutofillHintProperties(W3cHints.ORGANIZATION,
|
||||
SaveInfo.SAVE_DATA_TYPE_GENERIC, PARTITION_OTHER,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField =
|
||||
new FilledAutofillField(W3cHints.ORGANIZATION);
|
||||
filledAutofillField.setTextValue("org" + seed);
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
|
||||
.put(W3cHints.STREET_ADDRESS, new AutofillHintProperties(
|
||||
W3cHints.STREET_ADDRESS, SaveInfo.SAVE_DATA_TYPE_ADDRESS,
|
||||
PARTITION_ADDRESS,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField =
|
||||
new FilledAutofillField(W3cHints.STREET_ADDRESS);
|
||||
filledAutofillField.setTextValue(
|
||||
"" + seed + " Fake Ln, Fake, FA, FAA 10001");
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT))
|
||||
.put(W3cHints.ADDRESS_LINE1, new AutofillHintProperties(W3cHints.ADDRESS_LINE1,
|
||||
SaveInfo.SAVE_DATA_TYPE_ADDRESS,
|
||||
PARTITION_ADDRESS,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField =
|
||||
new FilledAutofillField(W3cHints.ADDRESS_LINE1);
|
||||
filledAutofillField.setTextValue("" + seed + " Fake Ln");
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT))
|
||||
.put(W3cHints.ADDRESS_LINE2, new AutofillHintProperties(W3cHints.ADDRESS_LINE2,
|
||||
SaveInfo.SAVE_DATA_TYPE_ADDRESS, PARTITION_ADDRESS,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField =
|
||||
new FilledAutofillField(W3cHints.ADDRESS_LINE2);
|
||||
filledAutofillField.setTextValue("Apt. " + seed);
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT))
|
||||
.put(W3cHints.ADDRESS_LINE3, new AutofillHintProperties(W3cHints.ADDRESS_LINE3,
|
||||
SaveInfo.SAVE_DATA_TYPE_ADDRESS, PARTITION_ADDRESS,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField =
|
||||
new FilledAutofillField(W3cHints.ADDRESS_LINE3);
|
||||
filledAutofillField.setTextValue("FA" + seed + ", FA, FAA");
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT))
|
||||
.put(W3cHints.ADDRESS_LEVEL4, new AutofillHintProperties(
|
||||
W3cHints.ADDRESS_LEVEL4, SaveInfo.SAVE_DATA_TYPE_ADDRESS,
|
||||
PARTITION_ADDRESS,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField =
|
||||
new FilledAutofillField(W3cHints.ADDRESS_LEVEL4);
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT))
|
||||
.put(W3cHints.ADDRESS_LEVEL3, new AutofillHintProperties(
|
||||
W3cHints.ADDRESS_LEVEL3, SaveInfo.SAVE_DATA_TYPE_ADDRESS,
|
||||
PARTITION_ADDRESS,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField =
|
||||
new FilledAutofillField(W3cHints.ADDRESS_LEVEL3);
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT))
|
||||
.put(W3cHints.ADDRESS_LEVEL2, new AutofillHintProperties(
|
||||
W3cHints.ADDRESS_LEVEL2, SaveInfo.SAVE_DATA_TYPE_ADDRESS,
|
||||
PARTITION_ADDRESS,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField =
|
||||
new FilledAutofillField(W3cHints.ADDRESS_LEVEL2);
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT))
|
||||
.put(W3cHints.ADDRESS_LEVEL1, new AutofillHintProperties(
|
||||
W3cHints.ADDRESS_LEVEL1, SaveInfo.SAVE_DATA_TYPE_ADDRESS,
|
||||
PARTITION_ADDRESS,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField =
|
||||
new FilledAutofillField(W3cHints.ADDRESS_LEVEL1);
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT))
|
||||
.put(W3cHints.COUNTRY, new AutofillHintProperties(W3cHints.COUNTRY,
|
||||
SaveInfo.SAVE_DATA_TYPE_ADDRESS, PARTITION_ADDRESS,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField =
|
||||
new FilledAutofillField(W3cHints.COUNTRY);
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
|
||||
.put(W3cHints.COUNTRY_NAME, new AutofillHintProperties(W3cHints.COUNTRY_NAME,
|
||||
SaveInfo.SAVE_DATA_TYPE_ADDRESS, PARTITION_ADDRESS,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField =
|
||||
new FilledAutofillField(W3cHints.COUNTRY_NAME);
|
||||
CharSequence[] exampleCountries = {"USA", "Mexico", "Canada"};
|
||||
filledAutofillField.setListValue(exampleCountries,
|
||||
seed % exampleCountries.length);
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
|
||||
.put(W3cHints.POSTAL_CODE, new AutofillHintProperties(
|
||||
View.AUTOFILL_HINT_POSTAL_CODE, SaveInfo.SAVE_DATA_TYPE_ADDRESS,
|
||||
PARTITION_ADDRESS,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField =
|
||||
new FilledAutofillField(View.AUTOFILL_HINT_POSTAL_CODE);
|
||||
filledAutofillField.setTextValue("" + seed + seed + seed + seed +
|
||||
seed);
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT))
|
||||
.put(W3cHints.CC_NAME, new AutofillHintProperties(W3cHints.CC_NAME,
|
||||
SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD,
|
||||
PARTITION_CREDIT_CARD,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField =
|
||||
new FilledAutofillField(W3cHints.CC_NAME);
|
||||
filledAutofillField.setTextValue("firstname" + seed + "lastname" +
|
||||
seed);
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT))
|
||||
.put(W3cHints.CC_GIVEN_NAME, new AutofillHintProperties(W3cHints.CC_GIVEN_NAME,
|
||||
SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD, PARTITION_CREDIT_CARD,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField =
|
||||
new FilledAutofillField(W3cHints.CC_GIVEN_NAME);
|
||||
filledAutofillField.setTextValue("givenname" + seed);
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT))
|
||||
.put(W3cHints.CC_ADDITIONAL_NAME, new AutofillHintProperties(
|
||||
W3cHints.CC_ADDITIONAL_NAME, SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD,
|
||||
PARTITION_CREDIT_CARD,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField =
|
||||
new FilledAutofillField(W3cHints.CC_ADDITIONAL_NAME);
|
||||
filledAutofillField.setTextValue("addtlname" + seed);
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT))
|
||||
.put(W3cHints.CC_FAMILY_NAME, new AutofillHintProperties(
|
||||
W3cHints.CC_FAMILY_NAME, SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD,
|
||||
PARTITION_CREDIT_CARD,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField =
|
||||
new FilledAutofillField(W3cHints.CC_FAMILY_NAME);
|
||||
filledAutofillField.setTextValue("familyname" + seed);
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT))
|
||||
.put(W3cHints.CC_NUMBER, new AutofillHintProperties(
|
||||
View.AUTOFILL_HINT_CREDIT_CARD_NUMBER,
|
||||
SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD, PARTITION_CREDIT_CARD,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField = new FilledAutofillField(
|
||||
View.AUTOFILL_HINT_CREDIT_CARD_NUMBER);
|
||||
filledAutofillField.setTextValue("" + seed + "234567");
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT))
|
||||
.put(W3cHints.CC_EXPIRATION, new AutofillHintProperties(
|
||||
View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE,
|
||||
SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD, PARTITION_CREDIT_CARD,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField = new FilledAutofillField(
|
||||
View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE);
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.set(Calendar.YEAR, calendar.get(Calendar.YEAR) + seed);
|
||||
filledAutofillField.setDateValue(calendar.getTimeInMillis());
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_DATE))
|
||||
.put(W3cHints.CC_EXPIRATION_MONTH, new AutofillHintProperties(
|
||||
View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH,
|
||||
SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD, PARTITION_CREDIT_CARD,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField = new FilledAutofillField(
|
||||
View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH);
|
||||
CharSequence[] months = monthRange();
|
||||
filledAutofillField.setListValue(months,
|
||||
seed % months.length);
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
|
||||
.put(W3cHints.CC_EXPIRATION_YEAR, new AutofillHintProperties(
|
||||
View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR,
|
||||
SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD, PARTITION_CREDIT_CARD,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField = new FilledAutofillField(
|
||||
View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR);
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
int expYear = calendar.get(Calendar.YEAR) + seed;
|
||||
calendar.set(Calendar.YEAR, expYear);
|
||||
filledAutofillField.setDateValue(calendar.getTimeInMillis());
|
||||
filledAutofillField.setTextValue("" + expYear);
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
|
||||
.put(W3cHints.CC_CSC, new AutofillHintProperties(
|
||||
View.AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE,
|
||||
SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD, PARTITION_CREDIT_CARD,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField = new FilledAutofillField(
|
||||
View.AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE);
|
||||
filledAutofillField.setTextValue("" + seed + seed + seed);
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT))
|
||||
.put(W3cHints.CC_TYPE, new AutofillHintProperties(W3cHints.CC_TYPE,
|
||||
SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD, PARTITION_CREDIT_CARD,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField =
|
||||
new FilledAutofillField(W3cHints.CC_TYPE);
|
||||
filledAutofillField.setTextValue("type" + seed);
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
|
||||
.put(W3cHints.TRANSACTION_CURRENCY, new AutofillHintProperties(
|
||||
W3cHints.TRANSACTION_CURRENCY, SaveInfo.SAVE_DATA_TYPE_GENERIC,
|
||||
PARTITION_OTHER,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField =
|
||||
new FilledAutofillField(W3cHints.TRANSACTION_CURRENCY);
|
||||
CharSequence[] exampleCurrencies = {"USD", "CAD", "KYD", "CRC"};
|
||||
filledAutofillField.setListValue(exampleCurrencies,
|
||||
seed % exampleCurrencies.length);
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
|
||||
.put(W3cHints.TRANSACTION_AMOUNT, new AutofillHintProperties(
|
||||
W3cHints.TRANSACTION_AMOUNT, SaveInfo.SAVE_DATA_TYPE_GENERIC,
|
||||
PARTITION_OTHER,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField =
|
||||
new FilledAutofillField(W3cHints.TRANSACTION_AMOUNT);
|
||||
filledAutofillField.setTextValue("" + seed * 100);
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
|
||||
.put(W3cHints.LANGUAGE, new AutofillHintProperties(W3cHints.LANGUAGE,
|
||||
SaveInfo.SAVE_DATA_TYPE_GENERIC, PARTITION_OTHER,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField =
|
||||
new FilledAutofillField(W3cHints.LANGUAGE);
|
||||
CharSequence[] exampleLanguages = {"Bulgarian", "Croatian", "Czech",
|
||||
"Danish", "Dutch", "English", "Estonian"};
|
||||
filledAutofillField.setListValue(exampleLanguages,
|
||||
seed % exampleLanguages.length);
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
|
||||
.put(W3cHints.BDAY, new AutofillHintProperties(W3cHints.BDAY,
|
||||
SaveInfo.SAVE_DATA_TYPE_GENERIC, PARTITION_OTHER,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField =
|
||||
new FilledAutofillField(W3cHints.BDAY);
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.set(Calendar.YEAR, calendar.get(Calendar.YEAR) - seed * 10);
|
||||
calendar.set(Calendar.MONTH, seed % 12);
|
||||
calendar.set(Calendar.DATE, seed % 27);
|
||||
filledAutofillField.setDateValue(calendar.getTimeInMillis());
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_DATE))
|
||||
.put(W3cHints.BDAY_DAY, new AutofillHintProperties(W3cHints.BDAY_DAY,
|
||||
SaveInfo.SAVE_DATA_TYPE_GENERIC, PARTITION_OTHER,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField =
|
||||
new FilledAutofillField(W3cHints.BDAY_DAY);
|
||||
filledAutofillField.setTextValue("" + seed % 27);
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
|
||||
.put(W3cHints.BDAY_MONTH, new AutofillHintProperties(W3cHints.BDAY_MONTH,
|
||||
SaveInfo.SAVE_DATA_TYPE_GENERIC, PARTITION_OTHER,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField =
|
||||
new FilledAutofillField(W3cHints.BDAY_MONTH);
|
||||
filledAutofillField.setTextValue("" + seed % 12);
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
|
||||
.put(W3cHints.BDAY_YEAR, new AutofillHintProperties(W3cHints.BDAY_YEAR,
|
||||
SaveInfo.SAVE_DATA_TYPE_GENERIC, PARTITION_OTHER,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField =
|
||||
new FilledAutofillField(W3cHints.BDAY_YEAR);
|
||||
int year = Calendar.getInstance().get(Calendar.YEAR) - seed * 10;
|
||||
filledAutofillField.setTextValue("" + year);
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
|
||||
.put(W3cHints.SEX, new AutofillHintProperties(W3cHints.SEX,
|
||||
SaveInfo.SAVE_DATA_TYPE_GENERIC, PARTITION_OTHER,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField =
|
||||
new FilledAutofillField(W3cHints.SEX);
|
||||
filledAutofillField.setTextValue("Other");
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
|
||||
.put(W3cHints.URL, new AutofillHintProperties(W3cHints.URL,
|
||||
SaveInfo.SAVE_DATA_TYPE_GENERIC, PARTITION_OTHER,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField =
|
||||
new FilledAutofillField(W3cHints.URL);
|
||||
filledAutofillField.setTextValue("http://google.com");
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT))
|
||||
.put(W3cHints.PHOTO, new AutofillHintProperties(W3cHints.PHOTO,
|
||||
SaveInfo.SAVE_DATA_TYPE_GENERIC, PARTITION_OTHER,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField =
|
||||
new FilledAutofillField(W3cHints.PHOTO);
|
||||
filledAutofillField.setTextValue("photo" + seed + ".jpg");
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
|
||||
.put(W3cHints.PREFIX_SECTION, new AutofillHintProperties(
|
||||
W3cHints.PREFIX_SECTION, SaveInfo.SAVE_DATA_TYPE_GENERIC,
|
||||
PARTITION_OTHER,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField =
|
||||
new FilledAutofillField(W3cHints.PREFIX_SECTION);
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
|
||||
.put(W3cHints.SHIPPING, new AutofillHintProperties(W3cHints.SHIPPING,
|
||||
SaveInfo.SAVE_DATA_TYPE_GENERIC, PARTITION_ADDRESS,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField =
|
||||
new FilledAutofillField(W3cHints.SHIPPING);
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
|
||||
.put(W3cHints.BILLING, new AutofillHintProperties(W3cHints.BILLING,
|
||||
SaveInfo.SAVE_DATA_TYPE_GENERIC, PARTITION_ADDRESS,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField =
|
||||
new FilledAutofillField(W3cHints.BILLING);
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
|
||||
.put(W3cHints.PREFIX_HOME, new AutofillHintProperties(W3cHints.PREFIX_HOME,
|
||||
SaveInfo.SAVE_DATA_TYPE_GENERIC, PARTITION_OTHER,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField =
|
||||
new FilledAutofillField(W3cHints.PREFIX_HOME);
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
|
||||
.put(W3cHints.PREFIX_WORK, new AutofillHintProperties(W3cHints.PREFIX_WORK,
|
||||
SaveInfo.SAVE_DATA_TYPE_GENERIC, PARTITION_OTHER,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField =
|
||||
new FilledAutofillField(W3cHints.PREFIX_WORK);
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
|
||||
.put(W3cHints.PREFIX_FAX, new AutofillHintProperties(W3cHints.PREFIX_FAX,
|
||||
SaveInfo.SAVE_DATA_TYPE_GENERIC, PARTITION_OTHER,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField =
|
||||
new FilledAutofillField(W3cHints.PREFIX_FAX);
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
|
||||
.put(W3cHints.PREFIX_PAGER, new AutofillHintProperties(W3cHints.PREFIX_PAGER,
|
||||
SaveInfo.SAVE_DATA_TYPE_GENERIC, PARTITION_OTHER,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField =
|
||||
new FilledAutofillField(W3cHints.PREFIX_PAGER);
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
|
||||
.put(W3cHints.TEL, new AutofillHintProperties(W3cHints.TEL,
|
||||
SaveInfo.SAVE_DATA_TYPE_GENERIC, PARTITION_OTHER,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField =
|
||||
new FilledAutofillField(W3cHints.TEL);
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT))
|
||||
.put(W3cHints.TEL_COUNTRY_CODE, new AutofillHintProperties(
|
||||
W3cHints.TEL_COUNTRY_CODE, SaveInfo.SAVE_DATA_TYPE_GENERIC,
|
||||
PARTITION_OTHER,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField =
|
||||
new FilledAutofillField(W3cHints.TEL_COUNTRY_CODE);
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
|
||||
.put(W3cHints.TEL_NATIONAL, new AutofillHintProperties(W3cHints.TEL_NATIONAL,
|
||||
SaveInfo.SAVE_DATA_TYPE_GENERIC, PARTITION_OTHER,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField =
|
||||
new FilledAutofillField(W3cHints.TEL_NATIONAL);
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
|
||||
.put(W3cHints.TEL_AREA_CODE, new AutofillHintProperties(
|
||||
W3cHints.TEL_AREA_CODE, SaveInfo.SAVE_DATA_TYPE_GENERIC,
|
||||
PARTITION_OTHER,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField =
|
||||
new FilledAutofillField(W3cHints.TEL_AREA_CODE);
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
|
||||
.put(W3cHints.TEL_LOCAL, new AutofillHintProperties(
|
||||
W3cHints.TEL_LOCAL, SaveInfo.SAVE_DATA_TYPE_GENERIC,
|
||||
PARTITION_OTHER,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField =
|
||||
new FilledAutofillField(W3cHints.TEL_LOCAL);
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
|
||||
.put(W3cHints.TEL_LOCAL_PREFIX, new AutofillHintProperties(
|
||||
W3cHints.TEL_LOCAL_PREFIX, SaveInfo.SAVE_DATA_TYPE_GENERIC,
|
||||
PARTITION_OTHER,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField =
|
||||
new FilledAutofillField(W3cHints.TEL_LOCAL_PREFIX);
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
|
||||
.put(W3cHints.TEL_LOCAL_SUFFIX, new AutofillHintProperties(
|
||||
W3cHints.TEL_LOCAL_SUFFIX, SaveInfo.SAVE_DATA_TYPE_GENERIC,
|
||||
PARTITION_OTHER,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField =
|
||||
new FilledAutofillField(W3cHints.TEL_LOCAL_SUFFIX);
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
|
||||
.put(W3cHints.TEL_EXTENSION, new AutofillHintProperties(W3cHints.TEL_EXTENSION,
|
||||
SaveInfo.SAVE_DATA_TYPE_GENERIC, PARTITION_OTHER,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField =
|
||||
new FilledAutofillField(W3cHints.TEL_EXTENSION);
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
|
||||
.put(W3cHints.EMAIL, new AutofillHintProperties(
|
||||
View.AUTOFILL_HINT_EMAIL_ADDRESS, SaveInfo.SAVE_DATA_TYPE_GENERIC,
|
||||
PARTITION_EMAIL,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField =
|
||||
new FilledAutofillField(View.AUTOFILL_HINT_EMAIL_ADDRESS);
|
||||
filledAutofillField.setTextValue("email" + seed);
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT))
|
||||
.put(W3cHints.IMPP, new AutofillHintProperties(W3cHints.IMPP,
|
||||
SaveInfo.SAVE_DATA_TYPE_EMAIL_ADDRESS, PARTITION_EMAIL,
|
||||
(seed) -> {
|
||||
FilledAutofillField filledAutofillField =
|
||||
new FilledAutofillField(W3cHints.IMPP);
|
||||
return filledAutofillField;
|
||||
}, View.AUTOFILL_TYPE_TEXT, View.AUTOFILL_TYPE_LIST))
|
||||
.build();
|
||||
|
||||
private AutofillHints() {
|
||||
}
|
||||
|
||||
public static boolean isValidTypeForHints(String[] hints, int type) {
|
||||
if (hints != null) {
|
||||
for (String hint : hints) {
|
||||
if (hint != null && sValidHints.containsKey(hint)) {
|
||||
boolean valid = sValidHints.get(hint).isValidType(type);
|
||||
if (valid) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isValidHint(String hint) {
|
||||
return sValidHints.containsKey(hint);
|
||||
}
|
||||
|
||||
public static int getSaveTypeForHints(String[] hints) {
|
||||
int saveType = 0;
|
||||
if (hints != null) {
|
||||
for (String hint : hints) {
|
||||
if (hint != null && sValidHints.containsKey(hint)) {
|
||||
saveType |= sValidHints.get(hint).getSaveType();
|
||||
}
|
||||
}
|
||||
}
|
||||
return saveType;
|
||||
}
|
||||
|
||||
public static FilledAutofillField getFakeField(String hint, int seed) {
|
||||
return sValidHints.get(hint).generateFakeField(seed);
|
||||
}
|
||||
|
||||
public static FilledAutofillFieldCollection getFakeFieldCollection(int partition, int seed) {
|
||||
FilledAutofillFieldCollection filledAutofillFieldCollection =
|
||||
new FilledAutofillFieldCollection();
|
||||
for (String hint : sValidHints.keySet()) {
|
||||
if (hint != null && sValidHints.get(hint).getPartition() == partition) {
|
||||
FilledAutofillField fakeField = getFakeField(hint, seed);
|
||||
filledAutofillFieldCollection.add(fakeField);
|
||||
}
|
||||
}
|
||||
return filledAutofillFieldCollection;
|
||||
}
|
||||
|
||||
private static String getStoredHintName(String hint) {
|
||||
return sValidHints.get(hint).getAutofillHint();
|
||||
}
|
||||
|
||||
public static void convertToStoredHintNames(String[] hints) {
|
||||
for (int i = 0; i < hints.length; i++) {
|
||||
hints[i] = getStoredHintName(hints[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private static CharSequence[] dayRange() {
|
||||
CharSequence[] days = new CharSequence[27];
|
||||
for (int i = 0; i < days.length; i++) {
|
||||
days[i] = Integer.toString(i);
|
||||
}
|
||||
return days;
|
||||
}
|
||||
|
||||
private static CharSequence[] monthRange() {
|
||||
CharSequence[] months = new CharSequence[12];
|
||||
for (int i = 0; i < months.length; i++) {
|
||||
months[i] = Integer.toString(i);
|
||||
}
|
||||
return months;
|
||||
}
|
||||
|
||||
public static String[] filterForSupportedHints(String[] hints) {
|
||||
String[] filteredHints = new String[hints.length];
|
||||
int i = 0;
|
||||
for (String hint : hints) {
|
||||
if (AutofillHints.isValidHint(hint)) {
|
||||
filteredHints[i++] = hint;
|
||||
} else {
|
||||
Log.w(AutofillHints.class.getName(), "Invalid autofill hint: " + hint);
|
||||
}
|
||||
}
|
||||
if (i == 0) {
|
||||
return null;
|
||||
}
|
||||
String[] finalFilteredHints = new String[i];
|
||||
System.arraycopy(filteredHints, 0, finalFilteredHints, 0, i);
|
||||
return finalFilteredHints;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.keepassdroid.autofill;
|
||||
|
||||
import com.keepassdroid.model.FilledAutofillField;
|
||||
|
||||
interface FakeFieldGenerator {
|
||||
FilledAutofillField generate(int seed);
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright 2017 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 2 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.keepassdroid.autofill;
|
||||
|
||||
import android.app.assist.AssistStructure;
|
||||
import android.content.IntentSender;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.CancellationSignal;
|
||||
import android.service.autofill.AutofillService;
|
||||
import android.service.autofill.FillCallback;
|
||||
import android.service.autofill.FillRequest;
|
||||
import android.service.autofill.FillResponse;
|
||||
import android.service.autofill.SaveCallback;
|
||||
import android.service.autofill.SaveRequest;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.RequiresApi;
|
||||
import android.util.Log;
|
||||
import android.view.autofill.AutofillId;
|
||||
import android.widget.RemoteViews;
|
||||
|
||||
import com.keepassdroid.AutoFillAuthActivity;
|
||||
import com.kunzisoft.keepass.R;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||
public class KeeAutofillService extends AutofillService {
|
||||
private static final String TAG = "KeeAutofillService";
|
||||
|
||||
@Override
|
||||
public void onFillRequest(@NonNull FillRequest request, @NonNull CancellationSignal cancellationSignal,
|
||||
@NonNull FillCallback callback) {
|
||||
AssistStructure structure = request.getFillContexts()
|
||||
.get(request.getFillContexts().size() - 1).getStructure();
|
||||
|
||||
final Bundle clientState = request.getClientState();
|
||||
|
||||
cancellationSignal.setOnCancelListener(() ->
|
||||
Log.e(TAG, "Cancel autofill not implemented in this sample.")
|
||||
);
|
||||
|
||||
// Parse AutoFill data in Activity
|
||||
StructureParser parser = new StructureParser(getApplicationContext(), structure);
|
||||
// TODO: try / catch on other places (onSave, auth activity, etc...)
|
||||
try {
|
||||
parser.parseForFill();
|
||||
} catch (SecurityException e) {
|
||||
// TODO: handle cases where DAL didn't pass by showing a custom UI asking the user
|
||||
// to confirm the mapping. Might require subclassing SecurityException.
|
||||
Log.e(TAG, "Security exception handling " + request);
|
||||
callback.onFailure(e.getMessage());
|
||||
return;
|
||||
}
|
||||
AutofillFieldMetadataCollection autofillFields = parser.getAutofillFields();
|
||||
FillResponse.Builder responseBuilder = new FillResponse.Builder();
|
||||
// Check user's settings for authenticating Responses and Datasets.
|
||||
AutofillId[] autofillIds = autofillFields.getAutofillIds();
|
||||
if (!Arrays.asList(autofillIds).isEmpty()) {
|
||||
// If the entire Autofill Response is authenticated, AuthActivity is used
|
||||
// to generate Response.
|
||||
IntentSender sender = AutoFillAuthActivity.getAuthIntentSenderForResponse(this);
|
||||
|
||||
RemoteViews presentation =
|
||||
new RemoteViews(getPackageName(), R.layout.autofill_service_unlock);
|
||||
presentation.setTextViewText(R.id.text, getString(R.string.autofill_sign_in_prompt));
|
||||
|
||||
responseBuilder
|
||||
.setAuthentication(autofillIds, sender, presentation);
|
||||
callback.onSuccess(responseBuilder.build());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveRequest(@NonNull SaveRequest request, @NonNull SaveCallback callback) {
|
||||
// Do nothing if is fill
|
||||
}
|
||||
}
|
||||
111
app/src/main/java/com/keepassdroid/autofill/StructureParser.java
Normal file
111
app/src/main/java/com/keepassdroid/autofill/StructureParser.java
Normal file
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.keepassdroid.autofill;
|
||||
|
||||
import android.app.assist.AssistStructure;
|
||||
import android.app.assist.AssistStructure.ViewNode;
|
||||
import android.app.assist.AssistStructure.WindowNode;
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.support.annotation.RequiresApi;
|
||||
import android.util.Log;
|
||||
|
||||
import com.keepassdroid.autofill.dataSource.SharedPrefsDigitalAssetLinksRepository;
|
||||
import com.keepassdroid.model.FilledAutofillFieldCollection;
|
||||
import com.kunzisoft.keepass.R;
|
||||
|
||||
/**
|
||||
* Parser for an AssistStructure object. This is invoked when the Autofill Service receives an
|
||||
* AssistStructure from the client Activity, representing its View hierarchy. In this sample, it
|
||||
* parses the hierarchy and collects autofill metadata from {@link ViewNode}s along the way.
|
||||
*/
|
||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||
final class StructureParser {
|
||||
private final AutofillFieldMetadataCollection mAutofillFields =
|
||||
new AutofillFieldMetadataCollection();
|
||||
private final Context mContext;
|
||||
private final AssistStructure mStructure;
|
||||
private FilledAutofillFieldCollection mFilledAutofillFieldCollection;
|
||||
|
||||
StructureParser(Context context, AssistStructure structure) {
|
||||
mContext = context;
|
||||
mStructure = structure;
|
||||
}
|
||||
|
||||
/**
|
||||
* Traverse AssistStructure and add ViewNode metadata to a flat list.
|
||||
*/
|
||||
public void parseForFill() {
|
||||
Log.d(getClass().getName(), "Parsing structure for " + mStructure.getActivityComponent());
|
||||
int nodes = mStructure.getWindowNodeCount();
|
||||
mFilledAutofillFieldCollection = new FilledAutofillFieldCollection();
|
||||
StringBuilder webDomain = new StringBuilder();
|
||||
for (int i = 0; i < nodes; i++) {
|
||||
WindowNode node = mStructure.getWindowNodeAt(i);
|
||||
ViewNode view = node.getRootViewNode();
|
||||
parseLocked(view, webDomain);
|
||||
}
|
||||
if (webDomain.length() > 0) {
|
||||
String packageName = mStructure.getActivityComponent().getPackageName();
|
||||
boolean valid = SharedPrefsDigitalAssetLinksRepository.getInstance().isValid(mContext,
|
||||
webDomain.toString(), packageName);
|
||||
if (!valid) {
|
||||
throw new SecurityException(mContext.getString(
|
||||
R.string.invalid_link_association, webDomain, packageName));
|
||||
}
|
||||
Log.d(getClass().getName(), "Domain " + webDomain + " is valid for " + packageName);
|
||||
} else {
|
||||
Log.d(getClass().getName(), "no web domain");
|
||||
}
|
||||
}
|
||||
|
||||
private void parseLocked(ViewNode viewNode, StringBuilder validWebDomain) {
|
||||
String webDomain = viewNode.getWebDomain();
|
||||
if (webDomain != null) {
|
||||
Log.d(getClass().getName(),"child web domain: " + webDomain);
|
||||
if (validWebDomain.length() > 0) {
|
||||
if (!webDomain.equals(validWebDomain.toString())) {
|
||||
throw new SecurityException("Found multiple web domains: valid= "
|
||||
+ validWebDomain + ", child=" + webDomain);
|
||||
}
|
||||
} else {
|
||||
validWebDomain.append(webDomain);
|
||||
}
|
||||
}
|
||||
|
||||
if (viewNode.getAutofillHints() != null) {
|
||||
String[] filteredHints = AutofillHints.filterForSupportedHints(
|
||||
viewNode.getAutofillHints());
|
||||
if (filteredHints != null && filteredHints.length > 0) {
|
||||
mAutofillFields.add(new AutofillFieldMetadata(viewNode));
|
||||
}
|
||||
}
|
||||
int childrenSize = viewNode.getChildCount();
|
||||
if (childrenSize > 0) {
|
||||
for (int i = 0; i < childrenSize; i++) {
|
||||
parseLocked(viewNode.getChildAt(i), validWebDomain);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public AutofillFieldMetadataCollection getAutofillFields() {
|
||||
return mAutofillFields;
|
||||
}
|
||||
|
||||
public FilledAutofillFieldCollection getClientFormData() {
|
||||
return mFilledAutofillFieldCollection;
|
||||
}
|
||||
}
|
||||
86
app/src/main/java/com/keepassdroid/autofill/W3cHints.java
Normal file
86
app/src/main/java/com/keepassdroid/autofill/W3cHints.java
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.keepassdroid.autofill;
|
||||
|
||||
public final class W3cHints {
|
||||
|
||||
// Supported W3C autofill tokens (https://html.spec.whatwg.org/multipage/forms.html#autofill)
|
||||
public static final String HONORIFIC_PREFIX = "honorific-prefix";
|
||||
public static final String NAME = "name";
|
||||
public static final String GIVEN_NAME = "given-name";
|
||||
public static final String ADDITIONAL_NAME = "additional-name";
|
||||
public static final String FAMILY_NAME = "family-name";
|
||||
public static final String HONORIFIC_SUFFIX = "honorific-suffix";
|
||||
public static final String USERNAME = "username";
|
||||
public static final String NEW_PASSWORD = "new-password";
|
||||
public static final String CURRENT_PASSWORD = "current-password";
|
||||
public static final String ORGANIZATION_TITLE = "organization-title";
|
||||
public static final String ORGANIZATION = "organization";
|
||||
public static final String STREET_ADDRESS = "street-address";
|
||||
public static final String ADDRESS_LINE1 = "address-line1";
|
||||
public static final String ADDRESS_LINE2 = "address-line2";
|
||||
public static final String ADDRESS_LINE3 = "address-line3";
|
||||
public static final String ADDRESS_LEVEL4 = "address-level4";
|
||||
public static final String ADDRESS_LEVEL3 = "address-level3";
|
||||
public static final String ADDRESS_LEVEL2 = "address-level2";
|
||||
public static final String ADDRESS_LEVEL1 = "address-level1";
|
||||
public static final String COUNTRY = "country";
|
||||
public static final String COUNTRY_NAME = "country-name";
|
||||
public static final String POSTAL_CODE = "postal-code";
|
||||
public static final String CC_NAME = "cc-name";
|
||||
public static final String CC_GIVEN_NAME = "cc-given-name";
|
||||
public static final String CC_ADDITIONAL_NAME = "cc-additional-name";
|
||||
public static final String CC_FAMILY_NAME = "cc-family-name";
|
||||
public static final String CC_NUMBER = "cc-number";
|
||||
public static final String CC_EXPIRATION = "cc-exp";
|
||||
public static final String CC_EXPIRATION_MONTH = "cc-exp-month";
|
||||
public static final String CC_EXPIRATION_YEAR = "cc-exp-year";
|
||||
public static final String CC_CSC = "cc-csc";
|
||||
public static final String CC_TYPE = "cc-type";
|
||||
public static final String TRANSACTION_CURRENCY = "transaction-currency";
|
||||
public static final String TRANSACTION_AMOUNT = "transaction-amount";
|
||||
public static final String LANGUAGE = "language";
|
||||
public static final String BDAY = "bday";
|
||||
public static final String BDAY_DAY = "bday-day";
|
||||
public static final String BDAY_MONTH = "bday-month";
|
||||
public static final String BDAY_YEAR = "bday-year";
|
||||
public static final String SEX = "sex";
|
||||
public static final String URL = "url";
|
||||
public static final String PHOTO = "photo";
|
||||
// Optional W3C prefixes
|
||||
public static final String PREFIX_SECTION = "section-";
|
||||
public static final String SHIPPING = "shipping";
|
||||
public static final String BILLING = "billing";
|
||||
// W3C prefixes below...
|
||||
public static final String PREFIX_HOME = "home";
|
||||
public static final String PREFIX_WORK = "work";
|
||||
public static final String PREFIX_FAX = "fax";
|
||||
public static final String PREFIX_PAGER = "pager";
|
||||
// ... require those suffix
|
||||
public static final String TEL = "tel";
|
||||
public static final String TEL_COUNTRY_CODE = "tel-country-code";
|
||||
public static final String TEL_NATIONAL = "tel-national";
|
||||
public static final String TEL_AREA_CODE = "tel-area-code";
|
||||
public static final String TEL_LOCAL = "tel-local";
|
||||
public static final String TEL_LOCAL_PREFIX = "tel-local-prefix";
|
||||
public static final String TEL_LOCAL_SUFFIX = "tel-local-suffix";
|
||||
public static final String TEL_EXTENSION = "tel_extension";
|
||||
public static final String EMAIL = "email";
|
||||
public static final String IMPP = "impp";
|
||||
|
||||
private W3cHints() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.keepassdroid.autofill.dataSource;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
/**
|
||||
* Helper format
|
||||
* <a href="https://developers.google.com/digital-asset-links/">Digital Asset Links</a> needs.
|
||||
*/
|
||||
public interface DigitalAssetLinksDataSource {
|
||||
|
||||
/**
|
||||
* Checks if the association between a web domain and a package is valid.
|
||||
*/
|
||||
boolean isValid(Context context, String webDomain, String packageName);
|
||||
|
||||
/**
|
||||
* Clears all cached data.
|
||||
*/
|
||||
void clear(Context context);
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.keepassdroid.autofill.dataSource;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
|
||||
/**
|
||||
* Singleton repository that caches the result of Digital Asset Links checks.
|
||||
*/
|
||||
public class SharedPrefsDigitalAssetLinksRepository implements DigitalAssetLinksDataSource {
|
||||
|
||||
private static SharedPrefsDigitalAssetLinksRepository sInstance;
|
||||
|
||||
private SharedPrefsDigitalAssetLinksRepository() {
|
||||
}
|
||||
|
||||
public static SharedPrefsDigitalAssetLinksRepository getInstance() {
|
||||
if (sInstance == null) {
|
||||
sInstance = new SharedPrefsDigitalAssetLinksRepository();
|
||||
}
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid(Context context, String webDomain, String packageName) {
|
||||
// TODO: implement caching. It could cache the whole domain -> (packagename, fingerprint),
|
||||
// but then either invalidate when the package change or when the DAL association times out
|
||||
// (the maxAge is part of the API response), or document that a real-life service
|
||||
// should do that.
|
||||
|
||||
return true;
|
||||
/*
|
||||
String fingerprint = null;
|
||||
try {
|
||||
fingerprint = SecurityHelper.getFingerprint(context, packageName);
|
||||
} catch (Exception e) {
|
||||
Log.e(getClass().getName(), "error getting fingerprint for " + packageName);
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
// TODO Security return SecurityHelper.isValid(webDomain, packageName, fingerprint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear(Context context) {
|
||||
// TODO: implement once if caches results or remove from the interface
|
||||
}
|
||||
}
|
||||
@@ -51,6 +51,6 @@ public class StorageAF {
|
||||
if (!supportsStorageFramework()) { return false; }
|
||||
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
|
||||
return prefs.getBoolean(ctx.getString(R.string.saf_key), ctx.getResources().getBoolean(R.bool.saf_default));
|
||||
return prefs.getBoolean(ctx.getString(R.string.settings_saf_key), ctx.getResources().getBoolean(R.bool.settings_saf_default));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ public class LoadDB extends RunnableOnFinish {
|
||||
mKey = key;
|
||||
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
|
||||
mRememberKeyfile = prefs.getBoolean(ctx.getString(R.string.keyfile_key), ctx.getResources().getBoolean(R.bool.keyfile_default));
|
||||
mRememberKeyfile = prefs.getBoolean(ctx.getString(R.string.settings_keyfile_key), ctx.getResources().getBoolean(R.bool.settings_keyfile_default));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -27,7 +27,7 @@ import com.keepassdroid.compat.BuildCompat;
|
||||
public class ReadOnlyDialog extends WarningDialog {
|
||||
|
||||
public ReadOnlyDialog(Context context) {
|
||||
super(context, R.string.show_read_only_warning);
|
||||
super(context, R.string.settings_show_read_only_warning);
|
||||
|
||||
warning = context.getString(R.string.read_only_warning);
|
||||
|
||||
|
||||
@@ -51,14 +51,14 @@ public class RecentFileHistory {
|
||||
ctx = c.getApplicationContext();
|
||||
|
||||
prefs = PreferenceManager.getDefaultSharedPreferences(c);
|
||||
enabled = prefs.getBoolean(ctx.getString(R.string.recentfile_key), ctx.getResources().getBoolean(R.bool.recentfile_default));
|
||||
enabled = prefs.getBoolean(ctx.getString(R.string.settings_recentfile_key), ctx.getResources().getBoolean(R.bool.settings_recentfile_default));
|
||||
listner = new OnSharedPreferenceChangeListener() {
|
||||
|
||||
@Override
|
||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
|
||||
String key) {
|
||||
if (key.equals(ctx.getString(R.string.recentfile_key))) {
|
||||
enabled = sharedPreferences.getBoolean(ctx.getString(R.string.recentfile_key), ctx.getResources().getBoolean(R.bool.recentfile_default));
|
||||
if (key.equals(ctx.getString(R.string.settings_recentfile_key))) {
|
||||
enabled = sharedPreferences.getBoolean(ctx.getString(R.string.settings_recentfile_key), ctx.getResources().getBoolean(R.bool.settings_recentfile_default));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.keepassdroid.model;
|
||||
|
||||
import android.os.Build;
|
||||
import android.support.annotation.RequiresApi;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.autofill.AutofillValue;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.gson.annotations.Expose;
|
||||
import com.keepassdroid.autofill.AutofillHints;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import static com.keepassdroid.autofill.AutofillHints.convertToStoredHintNames;
|
||||
import static com.keepassdroid.autofill.AutofillHints.filterForSupportedHints;
|
||||
|
||||
/**
|
||||
* JSON serializable data class containing the same data as an {@link AutofillValue}.
|
||||
*/
|
||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||
public class FilledAutofillField {
|
||||
@Expose
|
||||
private String mTextValue = null;
|
||||
@Expose
|
||||
private Long mDateValue = null;
|
||||
@Expose
|
||||
private Boolean mToggleValue = null;
|
||||
|
||||
//TODO add explicit mListValue
|
||||
|
||||
/**
|
||||
* Does not need to be serialized into persistent storage, so it's not exposed.
|
||||
*/
|
||||
private String[] mAutofillHints = null;
|
||||
|
||||
public FilledAutofillField(String... hints) {
|
||||
mAutofillHints = filterForSupportedHints(hints);
|
||||
convertToStoredHintNames(mAutofillHints);
|
||||
}
|
||||
|
||||
public void setListValue(CharSequence[] autofillOptions, int listValue) {
|
||||
/* Only set list value when a hint is allowed to store list values. */
|
||||
Preconditions.checkArgument(
|
||||
AutofillHints.isValidTypeForHints(mAutofillHints, View.AUTOFILL_TYPE_LIST),
|
||||
"List is invalid autofill type for hint(s) - %s",
|
||||
Arrays.toString(mAutofillHints));
|
||||
if (autofillOptions != null && autofillOptions.length > 0) {
|
||||
mTextValue = autofillOptions[listValue].toString();
|
||||
} else {
|
||||
Log.w(getClass().getName(), "autofillOptions should have at least one entry.");
|
||||
}
|
||||
}
|
||||
|
||||
public String[] getAutofillHints() {
|
||||
return mAutofillHints;
|
||||
}
|
||||
|
||||
public String getTextValue() {
|
||||
return mTextValue;
|
||||
}
|
||||
|
||||
public void setTextValue(CharSequence textValue) {
|
||||
/* Only set text value when a hint is allowed to store text values. */
|
||||
Preconditions.checkArgument(
|
||||
AutofillHints.isValidTypeForHints(mAutofillHints, View.AUTOFILL_TYPE_TEXT),
|
||||
"Text is invalid autofill type for hint(s) - %s",
|
||||
Arrays.toString(mAutofillHints));
|
||||
mTextValue = textValue.toString();
|
||||
}
|
||||
|
||||
public Long getDateValue() {
|
||||
return mDateValue;
|
||||
}
|
||||
|
||||
public void setDateValue(Long dateValue) {
|
||||
/* Only set date value when a hint is allowed to store date values. */
|
||||
Preconditions.checkArgument(
|
||||
AutofillHints.isValidTypeForHints(mAutofillHints, View.AUTOFILL_TYPE_DATE),
|
||||
"Date is invalid autofill type for hint(s) - %s"
|
||||
, Arrays.toString(mAutofillHints));
|
||||
mDateValue = dateValue;
|
||||
}
|
||||
|
||||
public Boolean getToggleValue() {
|
||||
return mToggleValue;
|
||||
}
|
||||
|
||||
public void setToggleValue(Boolean toggleValue) {
|
||||
/* Only set toggle value when a hint is allowed to store toggle values. */
|
||||
Preconditions.checkArgument(
|
||||
AutofillHints.isValidTypeForHints(mAutofillHints, View.AUTOFILL_TYPE_TOGGLE),
|
||||
"Toggle is invalid autofill type for hint(s) - %s",
|
||||
Arrays.toString(mAutofillHints));
|
||||
mToggleValue = toggleValue;
|
||||
}
|
||||
|
||||
public boolean isNull() {
|
||||
return mTextValue == null && mDateValue == null && mToggleValue == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
FilledAutofillField that = (FilledAutofillField) o;
|
||||
|
||||
if (mTextValue != null ? !mTextValue.equals(that.mTextValue) : that.mTextValue != null)
|
||||
return false;
|
||||
if (mDateValue != null ? !mDateValue.equals(that.mDateValue) : that.mDateValue != null)
|
||||
return false;
|
||||
return mToggleValue != null ? mToggleValue.equals(that.mToggleValue) :
|
||||
that.mToggleValue == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = mTextValue != null ? mTextValue.hashCode() : 0;
|
||||
result = 31 * result + (mDateValue != null ? mDateValue.hashCode() : 0);
|
||||
result = 31 * result + (mToggleValue != null ? mToggleValue.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,232 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.keepassdroid.model;
|
||||
|
||||
import android.os.Build;
|
||||
import android.service.autofill.Dataset;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.RequiresApi;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.autofill.AutofillId;
|
||||
import android.view.autofill.AutofillValue;
|
||||
|
||||
import com.google.gson.annotations.Expose;
|
||||
import com.keepassdroid.autofill.AutofillFieldMetadata;
|
||||
import com.keepassdroid.autofill.AutofillFieldMetadataCollection;
|
||||
import com.keepassdroid.autofill.AutofillHints;
|
||||
import com.keepassdroid.autofill.W3cHints;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* FilledAutofillFieldCollection is the model that holds all of the data on a client app's page,
|
||||
* plus the dataset name associated with it.
|
||||
*/
|
||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||
public final class FilledAutofillFieldCollection {
|
||||
@Expose
|
||||
private final HashMap<String, FilledAutofillField> mHintMap;
|
||||
@Expose
|
||||
private String mDatasetName;
|
||||
|
||||
public FilledAutofillFieldCollection() {
|
||||
this(null, new HashMap<>());
|
||||
}
|
||||
|
||||
public FilledAutofillFieldCollection(String datasetName, HashMap<String, FilledAutofillField> hintMap) {
|
||||
mHintMap = hintMap;
|
||||
mDatasetName = datasetName;
|
||||
}
|
||||
|
||||
private static boolean isW3cSectionPrefix(String hint) {
|
||||
return hint.startsWith(W3cHints.PREFIX_SECTION);
|
||||
}
|
||||
|
||||
private static boolean isW3cAddressType(String hint) {
|
||||
switch (hint) {
|
||||
case W3cHints.SHIPPING:
|
||||
case W3cHints.BILLING:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isW3cTypePrefix(String hint) {
|
||||
switch (hint) {
|
||||
case W3cHints.PREFIX_WORK:
|
||||
case W3cHints.PREFIX_FAX:
|
||||
case W3cHints.PREFIX_HOME:
|
||||
case W3cHints.PREFIX_PAGER:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isW3cTypeHint(String hint) {
|
||||
switch (hint) {
|
||||
case W3cHints.TEL:
|
||||
case W3cHints.TEL_COUNTRY_CODE:
|
||||
case W3cHints.TEL_NATIONAL:
|
||||
case W3cHints.TEL_AREA_CODE:
|
||||
case W3cHints.TEL_LOCAL:
|
||||
case W3cHints.TEL_LOCAL_PREFIX:
|
||||
case W3cHints.TEL_LOCAL_SUFFIX:
|
||||
case W3cHints.TEL_EXTENSION:
|
||||
case W3cHints.EMAIL:
|
||||
case W3cHints.IMPP:
|
||||
return true;
|
||||
}
|
||||
Log.w(FilledAutofillFieldCollection.class.getName(),"Invalid W3C type hint: " + hint);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the {@link Dataset}.
|
||||
*/
|
||||
public String getDatasetName() {
|
||||
return mDatasetName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link Dataset} name.
|
||||
*/
|
||||
public void setDatasetName(String datasetName) {
|
||||
mDatasetName = datasetName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a {@code FilledAutofillField} to the collection, indexed by all of its hints.
|
||||
*/
|
||||
public void add(@NonNull FilledAutofillField filledAutofillField) {
|
||||
String[] autofillHints = filledAutofillField.getAutofillHints();
|
||||
String nextHint = null;
|
||||
for (int i = 0; i < autofillHints.length; i++) {
|
||||
String hint = autofillHints[i];
|
||||
if (i < autofillHints.length - 1) {
|
||||
nextHint = autofillHints[i + 1];
|
||||
}
|
||||
// First convert the compound W3C autofill hints
|
||||
if (isW3cSectionPrefix(hint) && i < autofillHints.length - 1) {
|
||||
hint = autofillHints[++i];
|
||||
Log.d(getClass().getName(), "Hint is a W3C section prefix; using " + hint + " instead");
|
||||
if (i < autofillHints.length - 1) {
|
||||
nextHint = autofillHints[i + 1];
|
||||
}
|
||||
}
|
||||
if (isW3cTypePrefix(hint) && nextHint != null && isW3cTypeHint(nextHint)) {
|
||||
hint = nextHint;
|
||||
i++;
|
||||
Log.d(getClass().getName(), "Hint is a W3C type prefix; using "+ hint +" instead");
|
||||
}
|
||||
if (isW3cAddressType(hint) && nextHint != null) {
|
||||
hint = nextHint;
|
||||
i++;
|
||||
Log.d(getClass().getName(), "Hint is a W3C address prefix; using " + hint + " instead");
|
||||
}
|
||||
|
||||
// Then check if the "actual" hint is supported.
|
||||
if (AutofillHints.isValidHint(hint)) {
|
||||
mHintMap.put(hint, filledAutofillField);
|
||||
} else {
|
||||
Log.e(getClass().getName(), "Invalid hint: " + autofillHints[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates a {@link Dataset.Builder} with appropriate values for each {@link AutofillId}
|
||||
* in a {@code AutofillFieldMetadataCollection}.
|
||||
* <p>
|
||||
* In other words, it constructs an autofill
|
||||
* {@link Dataset.Builder} by applying saved values (from this {@code FilledAutofillFieldCollection})
|
||||
* to Views specified in a {@code AutofillFieldMetadataCollection}, which represents the current
|
||||
* page the user is on.
|
||||
*/
|
||||
public boolean applyToFields(AutofillFieldMetadataCollection autofillFieldMetadataCollection,
|
||||
Dataset.Builder datasetBuilder) {
|
||||
boolean setValueAtLeastOnce = false;
|
||||
List<String> allHints = autofillFieldMetadataCollection.getAllHints();
|
||||
for (int hintIndex = 0; hintIndex < allHints.size(); hintIndex++) {
|
||||
String hint = allHints.get(hintIndex);
|
||||
List<AutofillFieldMetadata> fillableAutofillFields =
|
||||
autofillFieldMetadataCollection.getFieldsForHint(hint);
|
||||
if (fillableAutofillFields == null) {
|
||||
continue;
|
||||
}
|
||||
for (int autofillFieldIndex = 0; autofillFieldIndex < fillableAutofillFields.size(); autofillFieldIndex++) {
|
||||
FilledAutofillField filledAutofillField = mHintMap.get(hint);
|
||||
if (filledAutofillField == null) {
|
||||
continue;
|
||||
}
|
||||
AutofillFieldMetadata autofillFieldMetadata = fillableAutofillFields.get(autofillFieldIndex);
|
||||
AutofillId autofillId = autofillFieldMetadata.getId();
|
||||
int autofillType = autofillFieldMetadata.getAutofillType();
|
||||
switch (autofillType) {
|
||||
case View.AUTOFILL_TYPE_LIST:
|
||||
int listValue = autofillFieldMetadata.getAutofillOptionIndex(filledAutofillField.getTextValue());
|
||||
if (listValue != -1) {
|
||||
datasetBuilder.setValue(autofillId, AutofillValue.forList(listValue));
|
||||
setValueAtLeastOnce = true;
|
||||
}
|
||||
break;
|
||||
case View.AUTOFILL_TYPE_DATE:
|
||||
Long dateValue = filledAutofillField.getDateValue();
|
||||
if (dateValue != null) {
|
||||
datasetBuilder.setValue(autofillId, AutofillValue.forDate(dateValue));
|
||||
setValueAtLeastOnce = true;
|
||||
}
|
||||
break;
|
||||
case View.AUTOFILL_TYPE_TEXT:
|
||||
String textValue = filledAutofillField.getTextValue();
|
||||
if (textValue != null) {
|
||||
datasetBuilder.setValue(autofillId, AutofillValue.forText(textValue));
|
||||
setValueAtLeastOnce = true;
|
||||
}
|
||||
break;
|
||||
case View.AUTOFILL_TYPE_TOGGLE:
|
||||
Boolean toggleValue = filledAutofillField.getToggleValue();
|
||||
if (toggleValue != null) {
|
||||
datasetBuilder.setValue(autofillId, AutofillValue.forToggle(toggleValue));
|
||||
setValueAtLeastOnce = true;
|
||||
}
|
||||
break;
|
||||
case View.AUTOFILL_TYPE_NONE:
|
||||
default:
|
||||
Log.w(getClass().getName(), "Invalid autofill type - " + autofillType);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return setValueAtLeastOnce;
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes in a list of autofill hints (autofillHints), usually associated with a View or set of
|
||||
* Views. Returns whether any of the filled fields on the page have at least 1 of these
|
||||
* autofillHints.
|
||||
*/
|
||||
public boolean helpsWithHints(List<String> autofillHints) {
|
||||
for (int i = 0; i < autofillHints.size(); i++) {
|
||||
String autofillHint = autofillHints.get(i);
|
||||
if (mHintMap.containsKey(autofillHint) && !mHintMap.get(autofillHint).isNull()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -50,7 +50,7 @@ public class SearchDbHelper {
|
||||
|
||||
private boolean omitBackup() {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mCtx);
|
||||
return prefs.getBoolean(mCtx.getString(R.string.omitbackup_key), mCtx.getResources().getBoolean(R.bool.omitbackup_default));
|
||||
return prefs.getBoolean(mCtx.getString(R.string.settings_omitbackup_key), mCtx.getResources().getBoolean(R.bool.settings_omitbackup_default));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright 2017 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 2 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.keepassdroid.settings;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.provider.Settings;
|
||||
import android.support.annotation.RequiresApi;
|
||||
import android.support.v14.preference.SwitchPreference;
|
||||
import android.support.v7.preference.Preference;
|
||||
import android.support.v7.preference.PreferenceFragmentCompat;
|
||||
import android.util.Log;
|
||||
import android.view.autofill.AutofillManager;
|
||||
|
||||
import com.kunzisoft.keepass.R;
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||
public class AutofillPreferenceFragment extends PreferenceFragmentCompat implements Preference.OnPreferenceClickListener {
|
||||
|
||||
private static final int REQUEST_CODE_SET_DEFAULT = 1;
|
||||
private AutofillManager mAutofillManager;
|
||||
private SwitchPreference enablePreference;
|
||||
|
||||
@Override
|
||||
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
|
||||
setPreferencesFromResource(R.xml.autofill_preferences, rootKey);
|
||||
mAutofillManager = getActivity().getSystemService(AutofillManager.class);
|
||||
|
||||
// add listeners for non-default actions
|
||||
enablePreference = (SwitchPreference) findPreference(getString(R.string.settings_autofill_enable_key));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
|
||||
enablePreference.setOnPreferenceClickListener(null);
|
||||
if (mAutofillManager != null && mAutofillManager.hasEnabledAutofillServices())
|
||||
enablePreference.setChecked(mAutofillManager.hasEnabledAutofillServices());
|
||||
enablePreference.setOnPreferenceClickListener(this);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
if (preference.getKey().equals(getString(R.string.settings_autofill_enable_key))) {
|
||||
setService(((SwitchPreference) preference).isChecked());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void setService(boolean enableService) {
|
||||
if (enableService) {
|
||||
startEnableService();
|
||||
} else {
|
||||
disableService();
|
||||
}
|
||||
}
|
||||
|
||||
private void disableService() {
|
||||
if (mAutofillManager != null && mAutofillManager.hasEnabledAutofillServices()) {
|
||||
mAutofillManager.disableAutofillServices();
|
||||
} else {
|
||||
Log.d(getClass().getName(), "Sample service already disabled.");
|
||||
}
|
||||
}
|
||||
|
||||
private void startEnableService() {
|
||||
if (mAutofillManager != null && !mAutofillManager.hasEnabledAutofillServices()) {
|
||||
Intent intent = new Intent(Settings.ACTION_REQUEST_SET_AUTOFILL_SERVICE);
|
||||
intent.setData(Uri.parse("package:com.example.android.autofill.service"));
|
||||
Log.d(getClass().getName(), "enableService(): intent="+ intent);
|
||||
startActivityForResult(intent, REQUEST_CODE_SET_DEFAULT);
|
||||
} else {
|
||||
Log.d(getClass().getName(), "Sample service already enabled.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
package com.keepassdroid.settings;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.support.v7.preference.Preference;
|
||||
import android.support.v7.preference.PreferenceFragmentCompat;
|
||||
@@ -29,14 +31,20 @@ public class MainPreferenceFragment extends PreferenceFragmentCompat implements
|
||||
setPreferencesFromResource(R.xml.preferences, rootKey);
|
||||
|
||||
// add listeners for non-default actions
|
||||
Preference preference = findPreference(getString(R.string.app_key));
|
||||
Preference preference = findPreference(getString(R.string.settings_app_key));
|
||||
preference.setOnPreferenceClickListener(this);
|
||||
|
||||
preference = findPreference(getString(R.string.db_key));
|
||||
preference = findPreference(getString(R.string.settings_db_key));
|
||||
Database db = App.getDB();
|
||||
if (!(db.Loaded() && db.pm.appSettingsEnabled())) {
|
||||
Preference dbSettings = findPreference(getString(R.string.db_key));
|
||||
dbSettings.setEnabled(false);
|
||||
preference.setEnabled(false);
|
||||
} else {
|
||||
preference.setOnPreferenceClickListener(this);
|
||||
}
|
||||
|
||||
preference = findPreference(getString(R.string.settings_autofill_key));
|
||||
if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
|
||||
preference.setEnabled(false);
|
||||
} else {
|
||||
preference.setOnPreferenceClickListener(this);
|
||||
}
|
||||
@@ -45,14 +53,19 @@ public class MainPreferenceFragment extends PreferenceFragmentCompat implements
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
// here you should use the same keys as you used in the xml-file
|
||||
if (preference.getKey().equals(getString(R.string.app_key))) {
|
||||
if (preference.getKey().equals(getString(R.string.settings_app_key))) {
|
||||
mCallback.onNestedPreferenceSelected(NestedSettingsFragment.NESTED_SCREEN_APP_KEY);
|
||||
}
|
||||
|
||||
if (preference.getKey().equals(getString(R.string.db_key))) {
|
||||
if (preference.getKey().equals(getString(R.string.settings_db_key))) {
|
||||
mCallback.onNestedPreferenceSelected(NestedSettingsFragment.NESTED_SCREEN_DB_KEY);
|
||||
}
|
||||
|
||||
if (preference.getKey().equals(getString(R.string.settings_autofill_key))) {
|
||||
Intent intent = new Intent(getContext(), SettingsAutofillActivity.class);
|
||||
getActivity().startActivity(intent);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -55,47 +55,38 @@ public class NestedSettingsFragment extends PreferenceFragmentCompat {
|
||||
case NESTED_SCREEN_APP_KEY:
|
||||
setPreferencesFromResource(R.xml.app_preferences, rootKey);
|
||||
|
||||
Preference keyFile = findPreference(getString(R.string.keyfile_key));
|
||||
keyFile.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
||||
Preference keyFile = findPreference(getString(R.string.settings_keyfile_key));
|
||||
keyFile.setOnPreferenceChangeListener((preference, newValue) -> {
|
||||
Boolean value = (Boolean) newValue;
|
||||
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
Boolean value = (Boolean) newValue;
|
||||
|
||||
if (!value) {
|
||||
App.getFileHistory().deleteAllKeys();
|
||||
}
|
||||
|
||||
return true;
|
||||
if (!value) {
|
||||
App.getFileHistory().deleteAllKeys();
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
Preference recentHistory = findPreference(getString(R.string.recentfile_key));
|
||||
recentHistory.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
||||
Preference recentHistory = findPreference(getString(R.string.settings_recentfile_key));
|
||||
recentHistory.setOnPreferenceChangeListener((preference, newValue) -> {
|
||||
Boolean value = (Boolean) newValue;
|
||||
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
Boolean value = (Boolean) newValue;
|
||||
|
||||
if (value == null) {
|
||||
value = true;
|
||||
}
|
||||
|
||||
if (!value) {
|
||||
App.getFileHistory().deleteAll();
|
||||
}
|
||||
|
||||
return true;
|
||||
if (value == null) {
|
||||
value = true;
|
||||
}
|
||||
|
||||
if (!value) {
|
||||
App.getFileHistory().deleteAll();
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
Preference stylePreference = findPreference(getString(R.string.setting_style_key));
|
||||
stylePreference.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
String styleString = (String) newValue;
|
||||
Stylish.assignStyle(getActivity(), styleString);
|
||||
getActivity().recreate();
|
||||
return true;
|
||||
}
|
||||
Preference stylePreference = findPreference(getString(R.string.settings_style_key));
|
||||
stylePreference.setOnPreferenceChangeListener((preference, newValue) -> {
|
||||
String styleString = (String) newValue;
|
||||
Stylish.assignStyle(getActivity(), styleString);
|
||||
getActivity().recreate();
|
||||
return true;
|
||||
});
|
||||
|
||||
break;
|
||||
@@ -106,18 +97,15 @@ public class NestedSettingsFragment extends PreferenceFragmentCompat {
|
||||
Database db = App.getDB();
|
||||
if (db.Loaded() && db.pm.appSettingsEnabled()) {
|
||||
|
||||
Preference rounds = findPreference(getString(R.string.rounds_key));
|
||||
rounds.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
||||
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
setRounds(App.getDB(), preference);
|
||||
return true;
|
||||
}
|
||||
Preference rounds = findPreference(getString(R.string.settings_rounds_key));
|
||||
rounds.setOnPreferenceChangeListener((preference, newValue) -> {
|
||||
setRounds(App.getDB(), preference);
|
||||
return true;
|
||||
});
|
||||
|
||||
setRounds(db, rounds);
|
||||
|
||||
Preference algorithm = findPreference(getString(R.string.algorithm_key));
|
||||
Preference algorithm = findPreference(getString(R.string.settings_algorithm_key));
|
||||
setAlgorithm(db, algorithm);
|
||||
|
||||
} else {
|
||||
|
||||
@@ -25,10 +25,10 @@ import android.preference.PreferenceManager;
|
||||
|
||||
import com.kunzisoft.keepass.R;
|
||||
|
||||
public class PrefsUtil {
|
||||
public class PreferencesUtil {
|
||||
|
||||
public static float getListTextSize(Context ctx) {
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
|
||||
return Float.parseFloat(prefs.getString(ctx.getString(R.string.list_size_key), ctx.getString(R.string.list_size_default)));
|
||||
|
||||
return Float.parseFloat(prefs.getString(ctx.getString(R.string.settings_list_size_key), ctx.getString(R.string.list_size_default)));
|
||||
}
|
||||
}
|
||||
@@ -57,7 +57,7 @@ public class SettingsActivity extends StylishActivity implements MainPreferenceF
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(R.layout.activity_toolbar);
|
||||
toolbar = (Toolbar) findViewById(R.id.toolbar);
|
||||
toolbar = findViewById(R.id.toolbar);
|
||||
toolbar.setTitle(R.string.settings);
|
||||
setSupportActionBar(toolbar);
|
||||
assert getSupportActionBar() != null;
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2017 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 2 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.keepassdroid.settings;
|
||||
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.RequiresApi;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.view.MenuItem;
|
||||
|
||||
import com.kunzisoft.keepass.R;
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||
public class SettingsAutofillActivity extends SettingsActivity {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(R.layout.activity_toolbar);
|
||||
Toolbar toolbar = findViewById(R.id.toolbar);
|
||||
toolbar.setTitle(R.string.menu_autofill_settings);
|
||||
setSupportActionBar(toolbar);
|
||||
assert getSupportActionBar() != null;
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
|
||||
if (savedInstanceState == null) {
|
||||
getSupportFragmentManager().beginTransaction()
|
||||
.replace(R.id.fragment_container, new AutofillPreferenceFragment())
|
||||
.commit();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch ( item.getItemId() ) {
|
||||
case android.R.id.home:
|
||||
onBackPressed();
|
||||
break;
|
||||
}
|
||||
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@ public class Stylish {
|
||||
private static String themeString;
|
||||
|
||||
public static void init(Context context) {
|
||||
stylishPrefKey = context.getString(R.string.setting_style_key);
|
||||
stylishPrefKey = context.getString(R.string.settings_style_key);
|
||||
Log.d(Stylish.class.getName(), "Attatching to " + context.getPackageName());
|
||||
themeString = PreferenceManager.getDefaultSharedPreferences(context).getString(stylishPrefKey, context.getString(R.string.list_style_name_light));
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ public class TimeoutHelper {
|
||||
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(act);
|
||||
SharedPreferences.Editor edit = prefs.edit();
|
||||
edit.putLong(act.getString(R.string.timeout_key), time);
|
||||
edit.putLong(act.getString(R.string.settings_timeout_key), time);
|
||||
|
||||
EditorCompat.apply(edit);
|
||||
|
||||
@@ -59,14 +59,14 @@ public class TimeoutHelper {
|
||||
long cur_time = System.currentTimeMillis();
|
||||
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(act);
|
||||
long timeout_start = prefs.getLong(act.getString(R.string.timeout_key), -1);
|
||||
long timeout_start = prefs.getLong(act.getString(R.string.settings_timeout_key), -1);
|
||||
// The timeout never started
|
||||
if (timeout_start == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
String sTimeout = prefs.getString(act.getString(R.string.app_timeout_key), act.getString(R.string.clipboard_timeout_default));
|
||||
String sTimeout = prefs.getString(act.getString(R.string.settings_app_timeout_key), act.getString(R.string.clipboard_timeout_default));
|
||||
long timeout;
|
||||
try {
|
||||
timeout = Long.parseLong(sTimeout);
|
||||
|
||||
@@ -28,7 +28,7 @@ public class Timeout {
|
||||
|
||||
|
||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
|
||||
String sTimeout = prefs.getString(ctx.getString(R.string.app_timeout_key), ctx.getString(R.string.clipboard_timeout_default));
|
||||
String sTimeout = prefs.getString(ctx.getString(R.string.settings_app_timeout_key), ctx.getString(R.string.clipboard_timeout_default));
|
||||
|
||||
long timeout;
|
||||
try {
|
||||
|
||||
@@ -36,7 +36,7 @@ import com.keepassdroid.ProgressTask;
|
||||
import com.keepassdroid.app.App;
|
||||
import com.keepassdroid.database.PwEntry;
|
||||
import com.keepassdroid.database.edit.DeleteEntry;
|
||||
import com.keepassdroid.settings.PrefsUtil;
|
||||
import com.keepassdroid.settings.PreferencesUtil;
|
||||
|
||||
public class PwEntryView extends ClickView {
|
||||
|
||||
@@ -58,7 +58,7 @@ public class PwEntryView extends ClickView {
|
||||
|
||||
View ev = View.inflate(mAct, R.layout.list_entries_entry, null);
|
||||
mTv = (TextView) ev.findViewById(R.id.entry_text);
|
||||
mTv.setTextSize(PrefsUtil.getListTextSize(act));
|
||||
mTv.setTextSize(PreferencesUtil.getListTextSize(act));
|
||||
|
||||
populateView(ev, pw, pos);
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ import com.keepassdroid.GroupBaseActivity;
|
||||
import com.keepassdroid.app.App;
|
||||
import com.keepassdroid.database.PwGroup;
|
||||
import com.keepassdroid.database.PwGroupV3;
|
||||
import com.keepassdroid.settings.PrefsUtil;
|
||||
import com.keepassdroid.settings.PreferencesUtil;
|
||||
|
||||
|
||||
public class PwGroupView extends ClickView {
|
||||
@@ -60,7 +60,7 @@ public class PwGroupView extends ClickView {
|
||||
View gv = View.inflate(act, R.layout.list_entries_group, null);
|
||||
|
||||
mTv = (TextView) gv.findViewById(R.id.group_text);
|
||||
float size = PrefsUtil.getListTextSize(act);
|
||||
float size = PreferencesUtil.getListTextSize(act);
|
||||
mTv.setTextSize(size);
|
||||
|
||||
TextView label = (TextView) gv.findViewById(R.id.group_label);
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="?attr/iconPreferenceColor"
|
||||
android:pathData="M19,2h-4.18C14.4,0.84 13.3,0 12,0c-1.3,0 -2.4,0.84 -2.82,2L5,2c-1.1,0 -2,0.9 -2,2v16c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,4c0,-1.1 -0.9,-2 -2,-2zM12,2c0.55,0 1,0.45 1,1s-0.45,1 -1,1 -1,-0.45 -1,-1 0.45,-1 1,-1zM19,20L5,20L5,4h2v3h10L17,4h2v16z"/>
|
||||
</vector>
|
||||
43
app/src/main/res/layout/autofill_service_unlock.xml
Normal file
43
app/src/main/res/layout/autofill_service_unlock.xml
Normal file
@@ -0,0 +1,43 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
-->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@android:color/white"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:minHeight="?android:attr/listPreferredItemHeightSmall"
|
||||
android:paddingRight="12dp"
|
||||
android:paddingEnd="12dp"
|
||||
android:paddingLeft="12dp"
|
||||
android:paddingStart="12dp"
|
||||
android:textAppearance="?android:attr/textAppearanceListItemSmall" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginRight="12dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:src="@drawable/ic_lock_white_24dp"
|
||||
android:tint="?attr/colorPrimary"/>
|
||||
</LinearLayout>
|
||||
@@ -1,4 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
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 2 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/>.
|
||||
-->
|
||||
<resources>
|
||||
<bool name="saf_default">true</bool>
|
||||
<bool name="settings_saf_default">true</bool>
|
||||
</resources>
|
||||
@@ -1,4 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 2017 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 2 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/>.
|
||||
-->
|
||||
<resources>
|
||||
<attr name="toolbarAppearance" format="reference" />
|
||||
<attr name="toolbarPopupAppearance" format="reference" />
|
||||
|
||||
@@ -32,31 +32,34 @@
|
||||
<integer name="default_password_length" translatable="false">8</integer>
|
||||
|
||||
<!-- Preference settings -->
|
||||
<string name="algorithm_key" translatable="false">algorithm</string>
|
||||
<string name="app_key" translatable="false">app</string>
|
||||
<string name="app_timeout_key" translatable="false">app_timeout_key</string>
|
||||
<string name="clipboard_timeout_key" translatable="false">clip_timeout_key</string>
|
||||
<string name="db_key" translatable="false">db</string>
|
||||
<string name="rounds_key" translatable="false">rounds</string>
|
||||
<string name="keyfile_key" translatable="false">keyfile</string>
|
||||
<string name="maskpass_key" translatable="false">maskpass</string>
|
||||
<string name="omitbackup_key" translatable="false">omitbackup</string>
|
||||
<string name="recentfile_key" translatable="false">recentfile</string>
|
||||
<string name="list_size_key" translatable="false">list_size</string>
|
||||
<string name="show_beta_warning" translatable="false">show_beta_warning</string>
|
||||
<string name="show_read_only_warning" translatable="false">show_read_only_warning</string>
|
||||
<string name="sort_key" translatable="false">sort_key</string>
|
||||
<string name="timeout_key" translatable="false">timeout_key</string>
|
||||
<string name="saf_key" translatable="false">storage_access_framework_key</string>
|
||||
<string name="setting_style_key" translatable="false">setting_style_key</string>
|
||||
<string name="settings_app_key" translatable="false">settings_app_key</string>
|
||||
<string name="settings_db_key" translatable="false">settings_db_key</string>
|
||||
<string name="settings_autofill_key" translatable="false">settings_autofill_key</string>
|
||||
<string name="settings_algorithm_key" translatable="false">algorithm</string>
|
||||
<string name="settings_app_timeout_key" translatable="false">app_timeout_key</string>
|
||||
<string name="settings_clipboard_timeout_key" translatable="false">clip_timeout_key</string>
|
||||
<string name="settings_rounds_key" translatable="false">rounds</string>
|
||||
<string name="settings_keyfile_key" translatable="false">keyfile</string>
|
||||
<string name="settings_maskpass_key" translatable="false">maskpass</string>
|
||||
<string name="settings_omitbackup_key" translatable="false">omitbackup</string>
|
||||
<string name="settings_recentfile_key" translatable="false">recentfile</string>
|
||||
<string name="settings_list_size_key" translatable="false">list_size</string>
|
||||
<string name="settings_show_beta_warning" translatable="false">show_beta_warning</string>
|
||||
<string name="settings_show_read_only_warning" translatable="false">show_read_only_warning</string>
|
||||
<string name="settings_sort_key" translatable="false">sort_key</string>
|
||||
<string name="settings_timeout_key" translatable="false">timeout_key</string>
|
||||
<string name="settings_saf_key" translatable="false">storage_access_framework_key</string>
|
||||
<string name="settings_style_key" translatable="false">settings_style_key</string>
|
||||
<string name="settings_autofill_enable_key" translatable="false">settings_autofill_enable_key</string>
|
||||
|
||||
<bool name="settings_maskpass_default" translatable="false">true</bool>
|
||||
<bool name="settings_keyfile_default" translatable="false">true</bool>
|
||||
<bool name="settings_sort_default" translatable="false">true</bool>
|
||||
<bool name="settings_omitbackup_default" translatable="false">true</bool>
|
||||
<bool name="settings_recentfile_default" translatable="false">true</bool>
|
||||
<bool name="settings_saf_default" translatable="false">false</bool>
|
||||
<bool name="settings_autofill_enable_default" translatable="false">false</bool>
|
||||
|
||||
<bool name="maskpass_default" translatable="false">true</bool>
|
||||
<bool name="keyfile_default" translatable="false">true</bool>
|
||||
<bool name="sort_default" translatable="false">true</bool>
|
||||
<bool name="omitbackup_default" translatable="false">true</bool>
|
||||
<bool name="recentfile_default" translatable="false">true</bool>
|
||||
<bool name="saf_default" translatable="false">false</bool>
|
||||
|
||||
<string name="clipboard_timeout_default" translatable="false">300000</string>
|
||||
<string-array name="clipboard_timeout_values">
|
||||
<item translatable="false">30000</item>
|
||||
|
||||
@@ -135,6 +135,7 @@
|
||||
<string name="settings">Settings</string>
|
||||
<string name="menu_app_settings">Application settings</string>
|
||||
<string name="menu_db_settings">Database settings</string>
|
||||
<string name="menu_autofill_settings">Autofill settings</string>
|
||||
<string name="menu_delete">Delete</string>
|
||||
<string name="menu_donate">Donate</string>
|
||||
<string name="menu_edit">Edit</string>
|
||||
@@ -202,6 +203,11 @@
|
||||
<string name="history">History</string>
|
||||
<string name="appearance">Appearance</string>
|
||||
<string name="general">General</string>
|
||||
<string name="autofill">Autofill</string>
|
||||
<string name="autofill_service_name">KeepassDX Autofill Service</string>
|
||||
<string name="autofill_sign_in_prompt">Tap to sign in.</string>
|
||||
<string name="set_autofill_service">Set default Autofill service</string>
|
||||
<string name="invalid_link_association">Could not associate web domain %1$s with app %2$s</string>
|
||||
|
||||
<string-array name="clipboard_timeout_options">
|
||||
<item>30 seconds</item>
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
android:title="@string/general">
|
||||
|
||||
<ListPreference
|
||||
android:key="@string/clipboard_timeout_key"
|
||||
android:key="@string/settings_clipboard_timeout_key"
|
||||
android:title="@string/clipboard_timeout"
|
||||
android:summary="@string/clipboard_timeout_summary"
|
||||
android:entries="@array/clipboard_timeout_options"
|
||||
@@ -32,7 +32,7 @@
|
||||
android:dialogTitle="@string/clipboard_timeout"
|
||||
android:defaultValue="@string/clipboard_timeout_default"/>
|
||||
<ListPreference
|
||||
android:key="@string/app_timeout_key"
|
||||
android:key="@string/settings_app_timeout_key"
|
||||
android:title="@string/app_timeout"
|
||||
android:summary="@string/app_timeout_summary"
|
||||
android:entries="@array/clipboard_timeout_options"
|
||||
@@ -40,20 +40,20 @@
|
||||
android:dialogTitle="@string/app_timeout"
|
||||
android:defaultValue="@string/clipboard_timeout_default"/>
|
||||
<CheckBoxPreference
|
||||
android:key="@string/maskpass_key"
|
||||
android:key="@string/settings_maskpass_key"
|
||||
android:title="@string/maskpass_title"
|
||||
android:summary="@string/maskpass_summary"
|
||||
android:defaultValue="@bool/maskpass_default"/>
|
||||
android:defaultValue="@bool/settings_maskpass_default"/>
|
||||
<CheckBoxPreference
|
||||
android:summary="@string/omitbackup_summary"
|
||||
android:defaultValue="@bool/omitbackup_default"
|
||||
android:defaultValue="@bool/settings_omitbackup_default"
|
||||
android:title="@string/omitbackup_title"
|
||||
android:key="@string/omitbackup_key"/>
|
||||
android:key="@string/settings_omitbackup_key"/>
|
||||
<CheckBoxPreference
|
||||
android:summary="@string/use_saf_summary"
|
||||
android:defaultValue="@bool/saf_default"
|
||||
android:defaultValue="@bool/settings_saf_default"
|
||||
android:title="@string/use_saf_title"
|
||||
android:key="@string/saf_key"/>
|
||||
android:key="@string/settings_saf_key"/>
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
@@ -62,15 +62,15 @@
|
||||
|
||||
<CheckBoxPreference
|
||||
android:summary="@string/recentfile_summary"
|
||||
android:defaultValue="@bool/recentfile_default"
|
||||
android:defaultValue="@bool/settings_recentfile_default"
|
||||
android:title="@string/recentfile_title"
|
||||
android:key="@string/recentfile_key"/>
|
||||
android:key="@string/settings_recentfile_key"/>
|
||||
<CheckBoxPreference
|
||||
android:key="@string/keyfile_key"
|
||||
android:key="@string/settings_keyfile_key"
|
||||
android:title="@string/remember_keyfile_title"
|
||||
android:summary="@string/remember_keyfile_summary"
|
||||
android:dependency="@string/recentfile_key"
|
||||
android:defaultValue="@bool/keyfile_default"/>
|
||||
android:dependency="@string/settings_recentfile_key"
|
||||
android:defaultValue="@bool/settings_keyfile_default"/>
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
@@ -80,12 +80,12 @@
|
||||
<ListPreference
|
||||
android:title="@string/style_choose_title"
|
||||
android:summary="@string/style_choose_summary"
|
||||
android:key="@string/setting_style_key"
|
||||
android:key="@string/settings_style_key"
|
||||
android:defaultValue="@string/list_style_name_light"
|
||||
android:entries="@array/list_style_names"
|
||||
android:entryValues="@array/list_style_values" />
|
||||
<ListPreference
|
||||
android:key="@string/list_size_key"
|
||||
android:key="@string/settings_list_size_key"
|
||||
android:title="@string/list_size_title"
|
||||
android:summary="@string/list_size_summary"
|
||||
android:entries="@array/list_size_options"
|
||||
|
||||
25
app/src/main/res/xml/autofill_preferences.xml
Normal file
25
app/src/main/res/xml/autofill_preferences.xml
Normal file
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 2017 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 2 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/>.
|
||||
-->
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<SwitchPreference
|
||||
android:title="@string/set_autofill_service"
|
||||
android:defaultValue="@bool/settings_autofill_enable_default"
|
||||
android:key="@string/settings_autofill_enable_key"/>
|
||||
</PreferenceScreen>
|
||||
22
app/src/main/res/xml/dataset_service.xml
Normal file
22
app/src/main/res/xml/dataset_service.xml
Normal file
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
-->
|
||||
|
||||
<!--
|
||||
Attributes for the AutoFill service that tell the framework what will act as the Autofill service's
|
||||
Settings Activity. This is pointed to in the service's meta-data in the application's manifest.
|
||||
-->
|
||||
<autofill-service xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:settingsActivity="com.keepassdroid.settings.SettingsAutofillActivity" />
|
||||
@@ -24,11 +24,11 @@
|
||||
android:title="@string/general">
|
||||
|
||||
<Preference
|
||||
android:key="@string/algorithm_key"
|
||||
android:key="@string/settings_algorithm_key"
|
||||
android:title="@string/algorithm"
|
||||
android:enabled="false"/>
|
||||
<com.keepassdroid.settings.RoundsPreference
|
||||
android:key="@string/rounds_key"
|
||||
android:key="@string/settings_rounds_key"
|
||||
android:persistent="false"
|
||||
android:title="@string/rounds"
|
||||
android:dialogLayout="@layout/database_settings"
|
||||
|
||||
@@ -23,18 +23,27 @@
|
||||
<PreferenceCategory
|
||||
android:title="@string/application">
|
||||
<Preference
|
||||
android:key="@string/app_key"
|
||||
android:key="@string/settings_app_key"
|
||||
android:title="@string/menu_app_settings"
|
||||
android:icon="@drawable/ic_phone_android_white_24dp"
|
||||
android:icon="@drawable/ic_phone_android_prefs_24dp"
|
||||
android:persistent="false" />
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
android:title="@string/database">
|
||||
<Preference
|
||||
android:key="@string/db_key"
|
||||
android:key="@string/settings_db_key"
|
||||
android:title="@string/menu_db_settings"
|
||||
android:icon="@drawable/ic_data_usage_white_24dp"
|
||||
android:icon="@drawable/ic_data_usage_prefs_24dp"
|
||||
android:persistent="false" />
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory
|
||||
android:title="@string/autofill">
|
||||
<Preference
|
||||
android:key="@string/settings_autofill_key"
|
||||
android:title="@string/menu_autofill_settings"
|
||||
android:icon="@drawable/ic_content_paste_prefs_24dp"
|
||||
android:persistent="false" />
|
||||
</PreferenceCategory>
|
||||
</PreferenceScreen>
|
||||
|
||||
@@ -8,7 +8,7 @@ buildscript {
|
||||
}
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.0.0'
|
||||
classpath 'com.android.tools.build:gradle:3.0.1'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user