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>
|
</value>
|
||||||
</option>
|
</option>
|
||||||
</component>
|
</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" />
|
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectType">
|
<component name="ProjectType">
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
apply plugin: 'com.android.application'
|
apply plugin: 'com.android.application'
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion = 25
|
compileSdkVersion = 26
|
||||||
buildToolsVersion = "26.0.2"
|
buildToolsVersion = "26.0.2"
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "com.kunzisoft.keepass"
|
applicationId "com.kunzisoft.keepass"
|
||||||
minSdkVersion 14
|
minSdkVersion 14
|
||||||
targetSdkVersion 25
|
targetSdkVersion 26
|
||||||
versionCode = 1
|
versionCode = 1
|
||||||
versionName = "2.5.0.0beta1"
|
versionName = "2.5.0.0beta1"
|
||||||
|
|
||||||
@@ -52,18 +52,24 @@ android {
|
|||||||
buildConfigField "boolean", "GOOGLE_PLAY_VERSION", "true"
|
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"
|
def spongycastleVersion = "1.58.0.0"
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
androidTestCompile files('libs/junit4.jar')
|
androidTestImplementation files('libs/junit4.jar')
|
||||||
compile "com.android.support:appcompat-v7:$supportVersion"
|
implementation "com.android.support:appcompat-v7:$supportVersion"
|
||||||
compile "com.android.support:design:$supportVersion"
|
implementation "com.android.support:design:$supportVersion"
|
||||||
compile "com.android.support:preference-v7:$supportVersion"
|
implementation "com.android.support:preference-v7:$supportVersion"
|
||||||
compile "com.android.support:preference-v14:$supportVersion"
|
implementation "com.android.support:preference-v14:$supportVersion"
|
||||||
compile "com.madgag.spongycastle:core:$spongycastleVersion"
|
implementation "com.madgag.spongycastle:core:$spongycastleVersion"
|
||||||
compile "com.madgag.spongycastle:prov:$spongycastleVersion"
|
implementation "com.madgag.spongycastle:prov:$spongycastleVersion"
|
||||||
compile "joda-time:joda-time:2.9.9"
|
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 prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
|
||||||
SharedPreferences.Editor editor = prefs.edit();
|
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();
|
editor.commit();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -102,8 +102,26 @@
|
|||||||
<meta-data android:name="android.app.searchable" android:resource="@xml/searchable" />
|
<meta-data android:name="android.app.searchable" android:resource="@xml/searchable" />
|
||||||
</activity>
|
</activity>
|
||||||
<activity android:name="com.keepassdroid.settings.SettingsActivity" />
|
<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.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" />
|
<meta-data android:name="com.sec.android.support.multiwindow" android:value="true" />
|
||||||
</application>
|
</application>
|
||||||
</manifest>
|
</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
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
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);
|
super.onCreate(savedInstanceState);
|
||||||
setEntryView();
|
setEntryView();
|
||||||
@@ -428,7 +428,7 @@ public class EntryActivity extends LockCloseHideActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
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);
|
long clipClearTime = Long.parseLong(sClipClear);
|
||||||
|
|
||||||
|
|||||||
@@ -247,7 +247,7 @@ public abstract class GroupActivity extends GroupBaseActivity
|
|||||||
if (App.getDB().readOnly) {
|
if (App.getDB().readOnly) {
|
||||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
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 dialog = new ReadOnlyDialog(this);
|
||||||
dialog.show();
|
dialog.show();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -191,7 +191,7 @@ public abstract class GroupBaseActivity extends LockCloseListActivity {
|
|||||||
|
|
||||||
// Will be null if onPrepareOptionsMenu is called before onCreate
|
// Will be null if onPrepareOptionsMenu is called before onCreate
|
||||||
if (prefs != null) {
|
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;
|
int resId;
|
||||||
@@ -245,8 +245,8 @@ public abstract class GroupBaseActivity extends LockCloseListActivity {
|
|||||||
|
|
||||||
private void toggleSort() {
|
private void toggleSort() {
|
||||||
// Toggle setting
|
// Toggle setting
|
||||||
String sortKey = getString(R.string.sort_key);
|
String sortKey = getString(R.string.settings_sort_key);
|
||||||
boolean sortByName = prefs.getBoolean(sortKey, getResources().getBoolean(R.bool.sort_default));
|
boolean sortByName = prefs.getBoolean(sortKey, getResources().getBoolean(R.bool.settings_sort_default));
|
||||||
Editor editor = prefs.edit();
|
Editor editor = prefs.edit();
|
||||||
editor.putBoolean(sortKey, ! sortByName);
|
editor.putBoolean(sortKey, ! sortByName);
|
||||||
EditorCompat.apply(editor);
|
EditorCompat.apply(editor);
|
||||||
|
|||||||
@@ -194,7 +194,7 @@ public class PasswordActivity extends LockingActivity implements FingerPrintHelp
|
|||||||
prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||||
prefsNoBackup = getSharedPreferences("nobackup", Context.MODE_PRIVATE);
|
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);
|
setContentView(R.layout.password);
|
||||||
|
|
||||||
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
|
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 ) {
|
if ( sortLists ) {
|
||||||
groupsForViewing = new ArrayList<PwGroup>(mGroup.childGroups);
|
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; }
|
if (!supportsStorageFramework()) { return false; }
|
||||||
|
|
||||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
|
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;
|
mKey = key;
|
||||||
|
|
||||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
|
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
|
@Override
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ import com.keepassdroid.compat.BuildCompat;
|
|||||||
public class ReadOnlyDialog extends WarningDialog {
|
public class ReadOnlyDialog extends WarningDialog {
|
||||||
|
|
||||||
public ReadOnlyDialog(Context context) {
|
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);
|
warning = context.getString(R.string.read_only_warning);
|
||||||
|
|
||||||
|
|||||||
@@ -51,14 +51,14 @@ public class RecentFileHistory {
|
|||||||
ctx = c.getApplicationContext();
|
ctx = c.getApplicationContext();
|
||||||
|
|
||||||
prefs = PreferenceManager.getDefaultSharedPreferences(c);
|
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() {
|
listner = new OnSharedPreferenceChangeListener() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
|
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
|
||||||
String key) {
|
String key) {
|
||||||
if (key.equals(ctx.getString(R.string.recentfile_key))) {
|
if (key.equals(ctx.getString(R.string.settings_recentfile_key))) {
|
||||||
enabled = sharedPreferences.getBoolean(ctx.getString(R.string.recentfile_key), ctx.getResources().getBoolean(R.bool.recentfile_default));
|
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() {
|
private boolean omitBackup() {
|
||||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mCtx);
|
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;
|
package com.keepassdroid.settings;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.v7.preference.Preference;
|
import android.support.v7.preference.Preference;
|
||||||
import android.support.v7.preference.PreferenceFragmentCompat;
|
import android.support.v7.preference.PreferenceFragmentCompat;
|
||||||
@@ -29,14 +31,20 @@ public class MainPreferenceFragment extends PreferenceFragmentCompat implements
|
|||||||
setPreferencesFromResource(R.xml.preferences, rootKey);
|
setPreferencesFromResource(R.xml.preferences, rootKey);
|
||||||
|
|
||||||
// add listeners for non-default actions
|
// 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.setOnPreferenceClickListener(this);
|
||||||
|
|
||||||
preference = findPreference(getString(R.string.db_key));
|
preference = findPreference(getString(R.string.settings_db_key));
|
||||||
Database db = App.getDB();
|
Database db = App.getDB();
|
||||||
if (!(db.Loaded() && db.pm.appSettingsEnabled())) {
|
if (!(db.Loaded() && db.pm.appSettingsEnabled())) {
|
||||||
Preference dbSettings = findPreference(getString(R.string.db_key));
|
preference.setEnabled(false);
|
||||||
dbSettings.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 {
|
} else {
|
||||||
preference.setOnPreferenceClickListener(this);
|
preference.setOnPreferenceClickListener(this);
|
||||||
}
|
}
|
||||||
@@ -45,14 +53,19 @@ public class MainPreferenceFragment extends PreferenceFragmentCompat implements
|
|||||||
@Override
|
@Override
|
||||||
public boolean onPreferenceClick(Preference preference) {
|
public boolean onPreferenceClick(Preference preference) {
|
||||||
// here you should use the same keys as you used in the xml-file
|
// 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);
|
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);
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -55,10 +55,8 @@ public class NestedSettingsFragment extends PreferenceFragmentCompat {
|
|||||||
case NESTED_SCREEN_APP_KEY:
|
case NESTED_SCREEN_APP_KEY:
|
||||||
setPreferencesFromResource(R.xml.app_preferences, rootKey);
|
setPreferencesFromResource(R.xml.app_preferences, rootKey);
|
||||||
|
|
||||||
Preference keyFile = findPreference(getString(R.string.keyfile_key));
|
Preference keyFile = findPreference(getString(R.string.settings_keyfile_key));
|
||||||
keyFile.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
keyFile.setOnPreferenceChangeListener((preference, newValue) -> {
|
||||||
|
|
||||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
|
||||||
Boolean value = (Boolean) newValue;
|
Boolean value = (Boolean) newValue;
|
||||||
|
|
||||||
if (!value) {
|
if (!value) {
|
||||||
@@ -66,13 +64,10 @@ public class NestedSettingsFragment extends PreferenceFragmentCompat {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Preference recentHistory = findPreference(getString(R.string.recentfile_key));
|
Preference recentHistory = findPreference(getString(R.string.settings_recentfile_key));
|
||||||
recentHistory.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
recentHistory.setOnPreferenceChangeListener((preference, newValue) -> {
|
||||||
|
|
||||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
|
||||||
Boolean value = (Boolean) newValue;
|
Boolean value = (Boolean) newValue;
|
||||||
|
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
@@ -84,18 +79,14 @@ public class NestedSettingsFragment extends PreferenceFragmentCompat {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Preference stylePreference = findPreference(getString(R.string.setting_style_key));
|
Preference stylePreference = findPreference(getString(R.string.settings_style_key));
|
||||||
stylePreference.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
stylePreference.setOnPreferenceChangeListener((preference, newValue) -> {
|
||||||
@Override
|
|
||||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
|
||||||
String styleString = (String) newValue;
|
String styleString = (String) newValue;
|
||||||
Stylish.assignStyle(getActivity(), styleString);
|
Stylish.assignStyle(getActivity(), styleString);
|
||||||
getActivity().recreate();
|
getActivity().recreate();
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -106,18 +97,15 @@ public class NestedSettingsFragment extends PreferenceFragmentCompat {
|
|||||||
Database db = App.getDB();
|
Database db = App.getDB();
|
||||||
if (db.Loaded() && db.pm.appSettingsEnabled()) {
|
if (db.Loaded() && db.pm.appSettingsEnabled()) {
|
||||||
|
|
||||||
Preference rounds = findPreference(getString(R.string.rounds_key));
|
Preference rounds = findPreference(getString(R.string.settings_rounds_key));
|
||||||
rounds.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
rounds.setOnPreferenceChangeListener((preference, newValue) -> {
|
||||||
|
|
||||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
|
||||||
setRounds(App.getDB(), preference);
|
setRounds(App.getDB(), preference);
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
setRounds(db, rounds);
|
setRounds(db, rounds);
|
||||||
|
|
||||||
Preference algorithm = findPreference(getString(R.string.algorithm_key));
|
Preference algorithm = findPreference(getString(R.string.settings_algorithm_key));
|
||||||
setAlgorithm(db, algorithm);
|
setAlgorithm(db, algorithm);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -25,10 +25,10 @@ import android.preference.PreferenceManager;
|
|||||||
|
|
||||||
import com.kunzisoft.keepass.R;
|
import com.kunzisoft.keepass.R;
|
||||||
|
|
||||||
public class PrefsUtil {
|
public class PreferencesUtil {
|
||||||
|
|
||||||
public static float getListTextSize(Context ctx) {
|
public static float getListTextSize(Context ctx) {
|
||||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(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);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
setContentView(R.layout.activity_toolbar);
|
setContentView(R.layout.activity_toolbar);
|
||||||
toolbar = (Toolbar) findViewById(R.id.toolbar);
|
toolbar = findViewById(R.id.toolbar);
|
||||||
toolbar.setTitle(R.string.settings);
|
toolbar.setTitle(R.string.settings);
|
||||||
setSupportActionBar(toolbar);
|
setSupportActionBar(toolbar);
|
||||||
assert getSupportActionBar() != null;
|
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;
|
private static String themeString;
|
||||||
|
|
||||||
public static void init(Context context) {
|
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());
|
Log.d(Stylish.class.getName(), "Attatching to " + context.getPackageName());
|
||||||
themeString = PreferenceManager.getDefaultSharedPreferences(context).getString(stylishPrefKey, context.getString(R.string.list_style_name_light));
|
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 prefs = PreferenceManager.getDefaultSharedPreferences(act);
|
||||||
SharedPreferences.Editor edit = prefs.edit();
|
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);
|
EditorCompat.apply(edit);
|
||||||
|
|
||||||
@@ -59,14 +59,14 @@ public class TimeoutHelper {
|
|||||||
long cur_time = System.currentTimeMillis();
|
long cur_time = System.currentTimeMillis();
|
||||||
|
|
||||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(act);
|
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
|
// The timeout never started
|
||||||
if (timeout_start == -1) {
|
if (timeout_start == -1) {
|
||||||
return;
|
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;
|
long timeout;
|
||||||
try {
|
try {
|
||||||
timeout = Long.parseLong(sTimeout);
|
timeout = Long.parseLong(sTimeout);
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ public class Timeout {
|
|||||||
|
|
||||||
|
|
||||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
|
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;
|
long timeout;
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ import com.keepassdroid.ProgressTask;
|
|||||||
import com.keepassdroid.app.App;
|
import com.keepassdroid.app.App;
|
||||||
import com.keepassdroid.database.PwEntry;
|
import com.keepassdroid.database.PwEntry;
|
||||||
import com.keepassdroid.database.edit.DeleteEntry;
|
import com.keepassdroid.database.edit.DeleteEntry;
|
||||||
import com.keepassdroid.settings.PrefsUtil;
|
import com.keepassdroid.settings.PreferencesUtil;
|
||||||
|
|
||||||
public class PwEntryView extends ClickView {
|
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);
|
View ev = View.inflate(mAct, R.layout.list_entries_entry, null);
|
||||||
mTv = (TextView) ev.findViewById(R.id.entry_text);
|
mTv = (TextView) ev.findViewById(R.id.entry_text);
|
||||||
mTv.setTextSize(PrefsUtil.getListTextSize(act));
|
mTv.setTextSize(PreferencesUtil.getListTextSize(act));
|
||||||
|
|
||||||
populateView(ev, pw, pos);
|
populateView(ev, pw, pos);
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ import com.keepassdroid.GroupBaseActivity;
|
|||||||
import com.keepassdroid.app.App;
|
import com.keepassdroid.app.App;
|
||||||
import com.keepassdroid.database.PwGroup;
|
import com.keepassdroid.database.PwGroup;
|
||||||
import com.keepassdroid.database.PwGroupV3;
|
import com.keepassdroid.database.PwGroupV3;
|
||||||
import com.keepassdroid.settings.PrefsUtil;
|
import com.keepassdroid.settings.PreferencesUtil;
|
||||||
|
|
||||||
|
|
||||||
public class PwGroupView extends ClickView {
|
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);
|
View gv = View.inflate(act, R.layout.list_entries_group, null);
|
||||||
|
|
||||||
mTv = (TextView) gv.findViewById(R.id.group_text);
|
mTv = (TextView) gv.findViewById(R.id.group_text);
|
||||||
float size = PrefsUtil.getListTextSize(act);
|
float size = PreferencesUtil.getListTextSize(act);
|
||||||
mTv.setTextSize(size);
|
mTv.setTextSize(size);
|
||||||
|
|
||||||
TextView label = (TextView) gv.findViewById(R.id.group_label);
|
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"?>
|
<?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>
|
<resources>
|
||||||
<bool name="saf_default">true</bool>
|
<bool name="settings_saf_default">true</bool>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -1,4 +1,22 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?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>
|
<resources>
|
||||||
<attr name="toolbarAppearance" format="reference" />
|
<attr name="toolbarAppearance" format="reference" />
|
||||||
<attr name="toolbarPopupAppearance" format="reference" />
|
<attr name="toolbarPopupAppearance" format="reference" />
|
||||||
|
|||||||
@@ -32,30 +32,33 @@
|
|||||||
<integer name="default_password_length" translatable="false">8</integer>
|
<integer name="default_password_length" translatable="false">8</integer>
|
||||||
|
|
||||||
<!-- Preference settings -->
|
<!-- Preference settings -->
|
||||||
<string name="algorithm_key" translatable="false">algorithm</string>
|
<string name="settings_app_key" translatable="false">settings_app_key</string>
|
||||||
<string name="app_key" translatable="false">app</string>
|
<string name="settings_db_key" translatable="false">settings_db_key</string>
|
||||||
<string name="app_timeout_key" translatable="false">app_timeout_key</string>
|
<string name="settings_autofill_key" translatable="false">settings_autofill_key</string>
|
||||||
<string name="clipboard_timeout_key" translatable="false">clip_timeout_key</string>
|
<string name="settings_algorithm_key" translatable="false">algorithm</string>
|
||||||
<string name="db_key" translatable="false">db</string>
|
<string name="settings_app_timeout_key" translatable="false">app_timeout_key</string>
|
||||||
<string name="rounds_key" translatable="false">rounds</string>
|
<string name="settings_clipboard_timeout_key" translatable="false">clip_timeout_key</string>
|
||||||
<string name="keyfile_key" translatable="false">keyfile</string>
|
<string name="settings_rounds_key" translatable="false">rounds</string>
|
||||||
<string name="maskpass_key" translatable="false">maskpass</string>
|
<string name="settings_keyfile_key" translatable="false">keyfile</string>
|
||||||
<string name="omitbackup_key" translatable="false">omitbackup</string>
|
<string name="settings_maskpass_key" translatable="false">maskpass</string>
|
||||||
<string name="recentfile_key" translatable="false">recentfile</string>
|
<string name="settings_omitbackup_key" translatable="false">omitbackup</string>
|
||||||
<string name="list_size_key" translatable="false">list_size</string>
|
<string name="settings_recentfile_key" translatable="false">recentfile</string>
|
||||||
<string name="show_beta_warning" translatable="false">show_beta_warning</string>
|
<string name="settings_list_size_key" translatable="false">list_size</string>
|
||||||
<string name="show_read_only_warning" translatable="false">show_read_only_warning</string>
|
<string name="settings_show_beta_warning" translatable="false">show_beta_warning</string>
|
||||||
<string name="sort_key" translatable="false">sort_key</string>
|
<string name="settings_show_read_only_warning" translatable="false">show_read_only_warning</string>
|
||||||
<string name="timeout_key" translatable="false">timeout_key</string>
|
<string name="settings_sort_key" translatable="false">sort_key</string>
|
||||||
<string name="saf_key" translatable="false">storage_access_framework_key</string>
|
<string name="settings_timeout_key" translatable="false">timeout_key</string>
|
||||||
<string name="setting_style_key" translatable="false">setting_style_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="maskpass_default" translatable="false">true</bool>
|
<bool name="settings_maskpass_default" translatable="false">true</bool>
|
||||||
<bool name="keyfile_default" translatable="false">true</bool>
|
<bool name="settings_keyfile_default" translatable="false">true</bool>
|
||||||
<bool name="sort_default" translatable="false">true</bool>
|
<bool name="settings_sort_default" translatable="false">true</bool>
|
||||||
<bool name="omitbackup_default" translatable="false">true</bool>
|
<bool name="settings_omitbackup_default" translatable="false">true</bool>
|
||||||
<bool name="recentfile_default" translatable="false">true</bool>
|
<bool name="settings_recentfile_default" translatable="false">true</bool>
|
||||||
<bool name="saf_default" translatable="false">false</bool>
|
<bool name="settings_saf_default" translatable="false">false</bool>
|
||||||
|
<bool name="settings_autofill_enable_default" translatable="false">false</bool>
|
||||||
|
|
||||||
<string name="clipboard_timeout_default" translatable="false">300000</string>
|
<string name="clipboard_timeout_default" translatable="false">300000</string>
|
||||||
<string-array name="clipboard_timeout_values">
|
<string-array name="clipboard_timeout_values">
|
||||||
|
|||||||
@@ -135,6 +135,7 @@
|
|||||||
<string name="settings">Settings</string>
|
<string name="settings">Settings</string>
|
||||||
<string name="menu_app_settings">Application settings</string>
|
<string name="menu_app_settings">Application settings</string>
|
||||||
<string name="menu_db_settings">Database 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_delete">Delete</string>
|
||||||
<string name="menu_donate">Donate</string>
|
<string name="menu_donate">Donate</string>
|
||||||
<string name="menu_edit">Edit</string>
|
<string name="menu_edit">Edit</string>
|
||||||
@@ -202,6 +203,11 @@
|
|||||||
<string name="history">History</string>
|
<string name="history">History</string>
|
||||||
<string name="appearance">Appearance</string>
|
<string name="appearance">Appearance</string>
|
||||||
<string name="general">General</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">
|
<string-array name="clipboard_timeout_options">
|
||||||
<item>30 seconds</item>
|
<item>30 seconds</item>
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
android:title="@string/general">
|
android:title="@string/general">
|
||||||
|
|
||||||
<ListPreference
|
<ListPreference
|
||||||
android:key="@string/clipboard_timeout_key"
|
android:key="@string/settings_clipboard_timeout_key"
|
||||||
android:title="@string/clipboard_timeout"
|
android:title="@string/clipboard_timeout"
|
||||||
android:summary="@string/clipboard_timeout_summary"
|
android:summary="@string/clipboard_timeout_summary"
|
||||||
android:entries="@array/clipboard_timeout_options"
|
android:entries="@array/clipboard_timeout_options"
|
||||||
@@ -32,7 +32,7 @@
|
|||||||
android:dialogTitle="@string/clipboard_timeout"
|
android:dialogTitle="@string/clipboard_timeout"
|
||||||
android:defaultValue="@string/clipboard_timeout_default"/>
|
android:defaultValue="@string/clipboard_timeout_default"/>
|
||||||
<ListPreference
|
<ListPreference
|
||||||
android:key="@string/app_timeout_key"
|
android:key="@string/settings_app_timeout_key"
|
||||||
android:title="@string/app_timeout"
|
android:title="@string/app_timeout"
|
||||||
android:summary="@string/app_timeout_summary"
|
android:summary="@string/app_timeout_summary"
|
||||||
android:entries="@array/clipboard_timeout_options"
|
android:entries="@array/clipboard_timeout_options"
|
||||||
@@ -40,20 +40,20 @@
|
|||||||
android:dialogTitle="@string/app_timeout"
|
android:dialogTitle="@string/app_timeout"
|
||||||
android:defaultValue="@string/clipboard_timeout_default"/>
|
android:defaultValue="@string/clipboard_timeout_default"/>
|
||||||
<CheckBoxPreference
|
<CheckBoxPreference
|
||||||
android:key="@string/maskpass_key"
|
android:key="@string/settings_maskpass_key"
|
||||||
android:title="@string/maskpass_title"
|
android:title="@string/maskpass_title"
|
||||||
android:summary="@string/maskpass_summary"
|
android:summary="@string/maskpass_summary"
|
||||||
android:defaultValue="@bool/maskpass_default"/>
|
android:defaultValue="@bool/settings_maskpass_default"/>
|
||||||
<CheckBoxPreference
|
<CheckBoxPreference
|
||||||
android:summary="@string/omitbackup_summary"
|
android:summary="@string/omitbackup_summary"
|
||||||
android:defaultValue="@bool/omitbackup_default"
|
android:defaultValue="@bool/settings_omitbackup_default"
|
||||||
android:title="@string/omitbackup_title"
|
android:title="@string/omitbackup_title"
|
||||||
android:key="@string/omitbackup_key"/>
|
android:key="@string/settings_omitbackup_key"/>
|
||||||
<CheckBoxPreference
|
<CheckBoxPreference
|
||||||
android:summary="@string/use_saf_summary"
|
android:summary="@string/use_saf_summary"
|
||||||
android:defaultValue="@bool/saf_default"
|
android:defaultValue="@bool/settings_saf_default"
|
||||||
android:title="@string/use_saf_title"
|
android:title="@string/use_saf_title"
|
||||||
android:key="@string/saf_key"/>
|
android:key="@string/settings_saf_key"/>
|
||||||
|
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
|
||||||
@@ -62,15 +62,15 @@
|
|||||||
|
|
||||||
<CheckBoxPreference
|
<CheckBoxPreference
|
||||||
android:summary="@string/recentfile_summary"
|
android:summary="@string/recentfile_summary"
|
||||||
android:defaultValue="@bool/recentfile_default"
|
android:defaultValue="@bool/settings_recentfile_default"
|
||||||
android:title="@string/recentfile_title"
|
android:title="@string/recentfile_title"
|
||||||
android:key="@string/recentfile_key"/>
|
android:key="@string/settings_recentfile_key"/>
|
||||||
<CheckBoxPreference
|
<CheckBoxPreference
|
||||||
android:key="@string/keyfile_key"
|
android:key="@string/settings_keyfile_key"
|
||||||
android:title="@string/remember_keyfile_title"
|
android:title="@string/remember_keyfile_title"
|
||||||
android:summary="@string/remember_keyfile_summary"
|
android:summary="@string/remember_keyfile_summary"
|
||||||
android:dependency="@string/recentfile_key"
|
android:dependency="@string/settings_recentfile_key"
|
||||||
android:defaultValue="@bool/keyfile_default"/>
|
android:defaultValue="@bool/settings_keyfile_default"/>
|
||||||
|
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
|
||||||
@@ -80,12 +80,12 @@
|
|||||||
<ListPreference
|
<ListPreference
|
||||||
android:title="@string/style_choose_title"
|
android:title="@string/style_choose_title"
|
||||||
android:summary="@string/style_choose_summary"
|
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:defaultValue="@string/list_style_name_light"
|
||||||
android:entries="@array/list_style_names"
|
android:entries="@array/list_style_names"
|
||||||
android:entryValues="@array/list_style_values" />
|
android:entryValues="@array/list_style_values" />
|
||||||
<ListPreference
|
<ListPreference
|
||||||
android:key="@string/list_size_key"
|
android:key="@string/settings_list_size_key"
|
||||||
android:title="@string/list_size_title"
|
android:title="@string/list_size_title"
|
||||||
android:summary="@string/list_size_summary"
|
android:summary="@string/list_size_summary"
|
||||||
android:entries="@array/list_size_options"
|
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">
|
android:title="@string/general">
|
||||||
|
|
||||||
<Preference
|
<Preference
|
||||||
android:key="@string/algorithm_key"
|
android:key="@string/settings_algorithm_key"
|
||||||
android:title="@string/algorithm"
|
android:title="@string/algorithm"
|
||||||
android:enabled="false"/>
|
android:enabled="false"/>
|
||||||
<com.keepassdroid.settings.RoundsPreference
|
<com.keepassdroid.settings.RoundsPreference
|
||||||
android:key="@string/rounds_key"
|
android:key="@string/settings_rounds_key"
|
||||||
android:persistent="false"
|
android:persistent="false"
|
||||||
android:title="@string/rounds"
|
android:title="@string/rounds"
|
||||||
android:dialogLayout="@layout/database_settings"
|
android:dialogLayout="@layout/database_settings"
|
||||||
|
|||||||
@@ -23,18 +23,27 @@
|
|||||||
<PreferenceCategory
|
<PreferenceCategory
|
||||||
android:title="@string/application">
|
android:title="@string/application">
|
||||||
<Preference
|
<Preference
|
||||||
android:key="@string/app_key"
|
android:key="@string/settings_app_key"
|
||||||
android:title="@string/menu_app_settings"
|
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" />
|
android:persistent="false" />
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
|
||||||
<PreferenceCategory
|
<PreferenceCategory
|
||||||
android:title="@string/database">
|
android:title="@string/database">
|
||||||
<Preference
|
<Preference
|
||||||
android:key="@string/db_key"
|
android:key="@string/settings_db_key"
|
||||||
android:title="@string/menu_db_settings"
|
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" />
|
android:persistent="false" />
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
</PreferenceScreen>
|
</PreferenceScreen>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ buildscript {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
dependencies {
|
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