Add Android autofill chooser and app binding
This commit is contained in:
@@ -10,6 +10,7 @@ import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
@@ -20,18 +21,7 @@ final class AutofillCacheStore {
|
||||
}
|
||||
|
||||
static Entry findBestMatch(Context context, String webDomain) {
|
||||
File cacheFile = findCacheFile(context);
|
||||
if (cacheFile == null) {
|
||||
Log.i(TAG, "autofill cache file not found");
|
||||
return null;
|
||||
}
|
||||
List<Entry> entries;
|
||||
try {
|
||||
entries = readEntries(cacheFile);
|
||||
} catch (IOException err) {
|
||||
Log.e(TAG, "failed to read autofill cache", err);
|
||||
return null;
|
||||
}
|
||||
List<Entry> entries = readEntries(context);
|
||||
if (entries.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
@@ -57,6 +47,50 @@ final class AutofillCacheStore {
|
||||
return chooseEntry(target, parentHost);
|
||||
}
|
||||
|
||||
static Entry findByID(Context context, String entryID) {
|
||||
if (entryID == null || entryID.trim().isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
for (Entry entry : readEntries(context)) {
|
||||
if (entryID.equals(entry.id)) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static List<Entry> chooserCandidates(Context context, String rawTarget) {
|
||||
List<Entry> entries = readEntries(context);
|
||||
if (entries.isEmpty()) {
|
||||
return entries;
|
||||
}
|
||||
Entry direct = findBestMatch(context, rawTarget);
|
||||
if (direct != null) {
|
||||
List<Entry> resolved = new ArrayList<>();
|
||||
resolved.add(direct);
|
||||
return resolved;
|
||||
}
|
||||
entries.sort(Comparator
|
||||
.comparing((Entry entry) -> entry.title.toLowerCase(Locale.US))
|
||||
.thenComparing(entry -> String.join("/", entry.path).toLowerCase(Locale.US))
|
||||
.thenComparing(entry -> entry.id));
|
||||
return entries;
|
||||
}
|
||||
|
||||
private static List<Entry> readEntries(Context context) {
|
||||
File cacheFile = findCacheFile(context);
|
||||
if (cacheFile == null) {
|
||||
Log.i(TAG, "autofill cache file not found");
|
||||
return new ArrayList<>();
|
||||
}
|
||||
try {
|
||||
return readEntries(cacheFile);
|
||||
} catch (IOException err) {
|
||||
Log.e(TAG, "failed to read autofill cache", err);
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
private static File findCacheFile(Context context) {
|
||||
List<File> candidates = new ArrayList<>();
|
||||
File filesDir = context.getFilesDir();
|
||||
@@ -103,16 +137,21 @@ final class AutofillCacheStore {
|
||||
}
|
||||
|
||||
private static Entry readEntry(JsonReader reader) throws IOException {
|
||||
String id = "";
|
||||
String title = "";
|
||||
String username = "";
|
||||
String password = "";
|
||||
String host = "";
|
||||
String url = "";
|
||||
List<String> targets = new ArrayList<>();
|
||||
List<String> path = new ArrayList<>();
|
||||
reader.beginObject();
|
||||
while (reader.hasNext()) {
|
||||
String name = reader.nextName();
|
||||
switch (name) {
|
||||
case "id":
|
||||
id = nextString(reader);
|
||||
break;
|
||||
case "title":
|
||||
title = nextString(reader);
|
||||
break;
|
||||
@@ -135,13 +174,20 @@ final class AutofillCacheStore {
|
||||
}
|
||||
reader.endArray();
|
||||
break;
|
||||
case "path":
|
||||
reader.beginArray();
|
||||
while (reader.hasNext()) {
|
||||
path.add(nextString(reader));
|
||||
}
|
||||
reader.endArray();
|
||||
break;
|
||||
default:
|
||||
reader.skipValue();
|
||||
break;
|
||||
}
|
||||
}
|
||||
reader.endObject();
|
||||
return new Entry(title, username, password, host, url, targets);
|
||||
return new Entry(id, title, username, password, host, url, targets, path);
|
||||
}
|
||||
|
||||
private static String nextString(JsonReader reader) throws IOException {
|
||||
@@ -293,20 +339,24 @@ final class AutofillCacheStore {
|
||||
}
|
||||
|
||||
static final class Entry {
|
||||
final String id;
|
||||
final String title;
|
||||
final String username;
|
||||
final String password;
|
||||
final String host;
|
||||
final String url;
|
||||
final List<String> targets;
|
||||
final List<String> path;
|
||||
|
||||
Entry(String title, String username, String password, String host, String url, List<String> targets) {
|
||||
Entry(String id, String title, String username, String password, String host, String url, List<String> targets, List<String> path) {
|
||||
this.id = id;
|
||||
this.title = title;
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
this.host = host;
|
||||
this.url = url;
|
||||
this.targets = new ArrayList<>(targets);
|
||||
this.path = new ArrayList<>(path);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user