aboutsummaryrefslogtreecommitdiffstats
path: root/OpenKeychain/src/main/java
diff options
context:
space:
mode:
authorVincent Breitmoser <valodim@mugenguild.com>2014-05-21 23:06:25 +0200
committerVincent Breitmoser <valodim@mugenguild.com>2014-05-21 23:06:51 +0200
commit952bb99a2467bb5c1c2988d33451df0249e04a42 (patch)
tree7c8cdeba0812cf84443880010cbedc73ab3a52d7 /OpenKeychain/src/main/java
parent6d7daec37f9ac7efbdd687c97ca45f9c9ddc5602 (diff)
parent8a2ffd8f90e9653ed69f945a94f6b9702dbdfff4 (diff)
downloadopen-keychain-952bb99a2467bb5c1c2988d33451df0249e04a42.tar.gz
open-keychain-952bb99a2467bb5c1c2988d33451df0249e04a42.tar.bz2
open-keychain-952bb99a2467bb5c1c2988d33451df0249e04a42.zip
Merge remote-tracking branch 'origin/master' into wrapped-key-ring
Conflicts: OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
Diffstat (limited to 'OpenKeychain/src/main/java')
-rw-r--r--OpenKeychain/src/main/java/android/support/v4/widget/FixedDrawerLayout.java16
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java (renamed from OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyServer.java)9
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java36
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeybaseKeyserver.java (renamed from OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeybaseKeyServer.java)103
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/Keyserver.java (renamed from OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeyServer.java)2
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java6
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java22
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java10
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java47
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyFragment.java21
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/HighlightQueryCursorAdapter.java66
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java19
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListKeybaseLoader.java12
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListServerLoader.java14
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SelectKeyCursorAdapter.java14
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Highlighter.java57
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/JWalk.java48
17 files changed, 316 insertions, 186 deletions
diff --git a/OpenKeychain/src/main/java/android/support/v4/widget/FixedDrawerLayout.java b/OpenKeychain/src/main/java/android/support/v4/widget/FixedDrawerLayout.java
index 1151818b6..6924e0b06 100644
--- a/OpenKeychain/src/main/java/android/support/v4/widget/FixedDrawerLayout.java
+++ b/OpenKeychain/src/main/java/android/support/v4/widget/FixedDrawerLayout.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ *
+ * 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 android.support.v4.widget;
import android.content.Context;
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyServer.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java
index 85ce6bfcc..f14978b39 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyServer.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java
@@ -52,7 +52,7 @@ import java.util.TimeZone;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-public class HkpKeyServer extends KeyServer {
+public class HkpKeyserver extends Keyserver {
private static class HttpError extends Exception {
private static final long serialVersionUID = 1718783705229428893L;
private int mCode;
@@ -148,7 +148,7 @@ public class HkpKeyServer extends KeyServer {
* connect using {@link #PORT_DEFAULT}. However, port may be specified after colon
* ("<code>hostname:port</code>", eg. "<code>p80.pool.sks-keyservers.net:80</code>").
*/
- public HkpKeyServer(String hostAndPort) {
+ public HkpKeyserver(String hostAndPort) {
String host = hostAndPort;
short port = PORT_DEFAULT;
final int colonPosition = hostAndPort.lastIndexOf(':');
@@ -161,7 +161,7 @@ public class HkpKeyServer extends KeyServer {
mPort = port;
}
- public HkpKeyServer(String host, short port) {
+ public HkpKeyserver(String host, short port) {
mHost = host;
mPort = port;
}
@@ -237,6 +237,7 @@ public class HkpKeyServer extends KeyServer {
final Matcher matcher = PUB_KEY_LINE.matcher(data);
while (matcher.find()) {
final ImportKeysListEntry entry = new ImportKeysListEntry();
+ entry.setQuery(query);
entry.setBitStrength(Integer.parseInt(matcher.group(3)));
@@ -247,7 +248,7 @@ public class HkpKeyServer extends KeyServer {
// see http://bit.ly/1d4bxbk and http://bit.ly/1gD1wwr
String fingerprintOrKeyId = matcher.group(1);
if (fingerprintOrKeyId.length() > 16) {
- entry.setFingerPrintHex(fingerprintOrKeyId.toLowerCase(Locale.US));
+ entry.setFingerprintHex(fingerprintOrKeyId.toLowerCase(Locale.US));
entry.setKeyIdHex("0x" + fingerprintOrKeyId.substring(fingerprintOrKeyId.length()
- 16, fingerprintOrKeyId.length()));
} else {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java
index 1199290e0..04b86e295 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java
@@ -45,11 +45,13 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
public String keyIdHex;
public boolean revoked;
public Date date; // TODO: not displayed
- public String fingerPrintHex;
+ public String fingerprintHex;
public int bitStrength;
public String algorithm;
public boolean secretKey;
public String mPrimaryUserId;
+ private String mExtraData;
+ private String mQuery;
private boolean mSelected;
@@ -66,7 +68,7 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
dest.writeLong(keyId);
dest.writeByte((byte) (revoked ? 1 : 0));
dest.writeSerializable(date);
- dest.writeString(fingerPrintHex);
+ dest.writeString(fingerprintHex);
dest.writeString(keyIdHex);
dest.writeInt(bitStrength);
dest.writeString(algorithm);
@@ -74,6 +76,7 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
dest.writeByte((byte) (mSelected ? 1 : 0));
dest.writeInt(mBytes.length);
dest.writeByteArray(mBytes);
+ dest.writeString(mExtraData);
}
public static final Creator<ImportKeysListEntry> CREATOR = new Creator<ImportKeysListEntry>() {
@@ -85,7 +88,7 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
vr.keyId = source.readLong();
vr.revoked = source.readByte() == 1;
vr.date = (Date) source.readSerializable();
- vr.fingerPrintHex = source.readString();
+ vr.fingerprintHex = source.readString();
vr.keyIdHex = source.readString();
vr.bitStrength = source.readInt();
vr.algorithm = source.readString();
@@ -93,6 +96,7 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
vr.mSelected = source.readByte() == 1;
vr.mBytes = new byte[source.readInt()];
source.readByteArray(vr.mBytes);
+ vr.mExtraData = source.readString();
return vr;
}
@@ -150,12 +154,12 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
this.date = date;
}
- public String getFingerPrintHex() {
- return fingerPrintHex;
+ public String getFingerprintHex() {
+ return fingerprintHex;
}
- public void setFingerPrintHex(String fingerPrintHex) {
- this.fingerPrintHex = fingerPrintHex;
+ public void setFingerprintHex(String fingerprintHex) {
+ this.fingerprintHex = fingerprintHex;
}
public int getBitStrength() {
@@ -198,6 +202,22 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
mPrimaryUserId = uid;
}
+ public String getExtraData() {
+ return mExtraData;
+ }
+
+ public void setExtraData(String extraData) {
+ mExtraData = extraData;
+ }
+
+ public String getQuery() {
+ return mQuery;
+ }
+
+ public void setQuery(String query) {
+ mQuery = query;
+ }
+
/**
* Constructor for later querying from keyserver
*/
@@ -260,7 +280,7 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
this.keyIdHex = PgpKeyHelper.convertKeyIdToHex(keyId);
this.revoked = key.isRevoked();
- this.fingerPrintHex = PgpKeyHelper.convertFingerprintToHex(key.getFingerprint());
+ this.fingerprintHex = PgpKeyHelper.convertFingerprintToHex(key.getFingerprint());
this.bitStrength = key.getBitStrength();
final int algorithm = key.getAlgorithm();
this.algorithm = PgpKeyHelper.getAlgorithmInfo(context, algorithm);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeybaseKeyServer.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeybaseKeyserver.java
index 7ffe123c0..5b66b50c5 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeybaseKeyServer.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeybaseKeyserver.java
@@ -21,6 +21,7 @@ import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.util.JWalk;
import org.sufficientlysecure.keychain.util.Log;
@@ -28,19 +29,20 @@ import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
-import java.util.GregorianCalendar;
-import java.util.TimeZone;
-import java.util.WeakHashMap;
-public class KeybaseKeyServer extends KeyServer {
-
- private WeakHashMap<String, String> mKeyCache = new WeakHashMap<String, String>();
+public class KeybaseKeyserver extends Keyserver {
+ private String mQuery;
@Override
public ArrayList<ImportKeysListEntry> search(String query) throws QueryException, TooManyResponses,
InsufficientQuery {
ArrayList<ImportKeysListEntry> results = new ArrayList<ImportKeysListEntry>();
+ if (query.startsWith("0x")) {
+ // cut off "0x" if a user is searching for a key id
+ query = query.substring(2);
+ }
+
JSONObject fromQuery = getFromKeybase("_/api/1.0/user/autocomplete.json?q=", query);
try {
@@ -50,59 +52,76 @@ public class KeybaseKeyServer extends KeyServer {
// only list them if they have a key
if (JWalk.optObject(match, "components", "key_fingerprint") != null) {
- results.add(makeEntry(match));
+ String keybaseId = JWalk.getString(match, "components", "username", "val");
+ String fingerprint = JWalk.getString(match, "components", "key_fingerprint", "val");
+ fingerprint = fingerprint.replace(" ", "").toUpperCase();
+
+ if (keybaseId.equals(query) || fingerprint.startsWith(query.toUpperCase())) {
+ results.add(makeEntry(match));
+ } else {
+ results.add(makeEntry(match));
+ }
}
}
} catch (Exception e) {
+ Log.e(Constants.TAG, "keybase result parsing error", e);
throw new QueryException("Unexpected structure in keybase search result: " + e.getMessage());
}
return results;
}
- private JSONObject getUser(String keybaseID) throws QueryException {
+ private JSONObject getUser(String keybaseId) throws QueryException {
try {
- return getFromKeybase("_/api/1.0/user/lookup.json?username=", keybaseID);
+ return getFromKeybase("_/api/1.0/user/lookup.json?username=", keybaseId);
} catch (Exception e) {
String detail = "";
- if (keybaseID != null) {
- detail = ". Query was for user '" + keybaseID + "'";
+ if (keybaseId != null) {
+ detail = ". Query was for user '" + keybaseId + "'";
}
throw new QueryException(e.getMessage() + detail);
}
}
private ImportKeysListEntry makeEntry(JSONObject match) throws QueryException, JSONException {
-
- String keybaseID = JWalk.getString(match, "components", "username", "val");
- String key_fingerprint = JWalk.getString(match, "components", "key_fingerprint", "val");
- key_fingerprint = key_fingerprint.replace(" ", "").toUpperCase();
- match = getUser(keybaseID);
-
final ImportKeysListEntry entry = new ImportKeysListEntry();
+ entry.setQuery(mQuery);
- // TODO: Fix; have suggested keybase provide this value to avoid search-time crypto calls
- entry.setBitStrength(4096);
- entry.setAlgorithm("RSA");
- entry.setKeyIdHex("0x" + key_fingerprint);
- entry.setRevoked(false);
+ String keybaseId = JWalk.getString(match, "components", "username", "val");
+ String fullName = JWalk.getString(match, "components", "full_name", "val");
+ String fingerprint = JWalk.getString(match, "components", "key_fingerprint", "val");
+ fingerprint = fingerprint.replace(" ", "").toUpperCase(); // not strictly necessary but doesn't hurt
+ entry.setFingerprintHex(fingerprint);
- // ctime
- final long creationDate = JWalk.getLong(match, "them", "public_keys", "primary", "ctime");
- final GregorianCalendar tmpGreg = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
- tmpGreg.setTimeInMillis(creationDate * 1000);
- entry.setDate(tmpGreg.getTime());
+ entry.setKeyIdHex("0x" + fingerprint.substring(Math.max(0, fingerprint.length() - 16)));
+ // store extra info, so we can query for the keybase id directly
+ entry.setExtraData(keybaseId);
- // key bits
- // we have to fetch the user object to construct the search-result list, so we might as
- // well (weakly) remember the key, in case they try to import it
- mKeyCache.put(keybaseID, JWalk.getString(match,"them", "public_keys", "primary", "bundle"));
+ final int algorithmId = JWalk.getInt(match, "components", "key_fingerprint", "algo");
+ entry.setAlgorithm(PgpKeyHelper.getAlgorithmInfo(algorithmId));
+ final int bitStrength = JWalk.getInt(match, "components", "key_fingerprint", "nbits");
+ entry.setBitStrength(bitStrength);
- // String displayName = JWalk.getString(match, "them", "profile", "full_name");
ArrayList<String> userIds = new ArrayList<String>();
- String name = "keybase.io/" + keybaseID + " <" + keybaseID + "@keybase.io>";
+ String name = fullName + " <keybase.io/" + keybaseId + ">";
userIds.add(name);
- userIds.add(keybaseID);
+ try {
+ userIds.add("github.com/" + JWalk.getString(match, "components", "github", "val"));
+ } catch (JSONException e) {
+ // ignore
+ }
+ try {
+ userIds.add("twitter.com/" + JWalk.getString(match, "components", "twitter", "val"));
+ } catch (JSONException e) {
+ // ignore
+ }
+ try {
+ JSONArray array = JWalk.getArray(match, "components", "websites");
+ JSONObject website = array.getJSONObject(0);
+ userIds.add(JWalk.getString(website, "val"));
+ } catch (JSONException e) {
+ // ignore
+ }
entry.setUserIds(userIds);
entry.setPrimaryUserId(name);
return entry;
@@ -142,20 +161,16 @@ public class KeybaseKeyServer extends KeyServer {
@Override
public String get(String id) throws QueryException {
- String key = mKeyCache.get(id);
- if (key == null) {
- try {
- JSONObject user = getUser(id);
- key = JWalk.getString(user, "them", "public_keys", "primary", "bundle");
- } catch (Exception e) {
- throw new QueryException(e.getMessage());
- }
+ try {
+ JSONObject user = getUser(id);
+ return JWalk.getString(user, "them", "public_keys", "primary", "bundle");
+ } catch (Exception e) {
+ throw new QueryException(e.getMessage());
}
- return key;
}
@Override
public void add(String armoredKey) throws AddKeyException {
throw new AddKeyException();
}
-} \ No newline at end of file
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeyServer.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/Keyserver.java
index d6ebca5a6..19591eda8 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeyServer.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/Keyserver.java
@@ -23,7 +23,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.util.List;
-public abstract class KeyServer {
+public abstract class Keyserver {
public static class QueryException extends Exception {
private static final long serialVersionUID = 2703768928624654512L;
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java
index 5c4604647..a55765542 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java
@@ -36,9 +36,9 @@ import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.service.KeychainIntentService;
import org.sufficientlysecure.keychain.keyimport.ImportKeysListEntry;
-import org.sufficientlysecure.keychain.keyimport.HkpKeyServer;
+import org.sufficientlysecure.keychain.keyimport.HkpKeyserver;
import org.sufficientlysecure.keychain.util.IterableIterator;
-import org.sufficientlysecure.keychain.keyimport.KeyServer.AddKeyException;
+import org.sufficientlysecure.keychain.keyimport.Keyserver.AddKeyException;
import org.sufficientlysecure.keychain.util.Log;
import java.io.ByteArrayOutputStream;
@@ -100,7 +100,7 @@ public class PgpImportExport {
}
}
- public boolean uploadKeyRingToServer(HkpKeyServer server, WrappedPublicKeyRing keyring) {
+ public boolean uploadKeyRingToServer(HkpKeyserver server, WrappedPublicKeyRing keyring) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ArmoredOutputStream aos = null;
try {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
index f0d01e2ce..b866bdf7f 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
@@ -35,6 +35,7 @@ import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.helper.FileHelper;
import org.sufficientlysecure.keychain.helper.OtherHelper;
import org.sufficientlysecure.keychain.helper.Preferences;
+import org.sufficientlysecure.keychain.keyimport.HkpKeyserver;
import org.sufficientlysecure.keychain.pgp.WrappedPublicKeyRing;
import org.sufficientlysecure.keychain.pgp.WrappedSecretKey;
import org.sufficientlysecure.keychain.pgp.WrappedSecretKeyRing;
@@ -54,9 +55,8 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.KeychainDatabase;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.keyimport.ImportKeysListEntry;
-import org.sufficientlysecure.keychain.keyimport.HkpKeyServer;
import org.sufficientlysecure.keychain.util.InputData;
-import org.sufficientlysecure.keychain.keyimport.KeybaseKeyServer;
+import org.sufficientlysecure.keychain.keyimport.KeybaseKeyserver;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.ProgressScaler;
@@ -721,7 +721,7 @@ public class KeychainIntentService extends IntentService
// and dataUri!
/* Operation */
- HkpKeyServer server = new HkpKeyServer(keyServer);
+ HkpKeyserver server = new HkpKeyserver(keyServer);
ProviderHelper providerHelper = new ProviderHelper(this);
WrappedPublicKeyRing keyring = providerHelper.getWrappedPublicKeyRing(dataUri);
@@ -740,11 +740,11 @@ public class KeychainIntentService extends IntentService
ArrayList<ImportKeysListEntry> entries = data.getParcelableArrayList(DOWNLOAD_KEY_LIST);
try {
- KeybaseKeyServer server = new KeybaseKeyServer();
+ KeybaseKeyserver server = new KeybaseKeyserver();
for (ImportKeysListEntry entry : entries) {
// the keybase handle is in userId(1)
- String keybaseID = entry.getUserIds().get(1);
- byte[] downloadedKeyBytes = server.get(keybaseID).getBytes();
+ String keybaseId = entry.getExtraData();
+ byte[] downloadedKeyBytes = server.get(keybaseId).getBytes();
// create PGPKeyRing object based on downloaded armored key
PGPKeyRing downloadedKey = null;
@@ -791,13 +791,13 @@ public class KeychainIntentService extends IntentService
String keyServer = data.getString(DOWNLOAD_KEY_SERVER);
// this downloads the keys and places them into the ImportKeysListEntry entries
- HkpKeyServer server = new HkpKeyServer(keyServer);
+ HkpKeyserver server = new HkpKeyserver(keyServer);
for (ImportKeysListEntry entry : entries) {
// if available use complete fingerprint for get request
byte[] downloadedKeyBytes;
- if (entry.getFingerPrintHex() != null) {
- downloadedKeyBytes = server.get("0x" + entry.getFingerPrintHex()).getBytes();
+ if (entry.getFingerprintHex() != null) {
+ downloadedKeyBytes = server.get("0x" + entry.getFingerprintHex()).getBytes();
} else {
downloadedKeyBytes = server.get(entry.getKeyIdHex()).getBytes();
}
@@ -807,10 +807,10 @@ public class KeychainIntentService extends IntentService
UncachedKeyRing.decodePubkeyFromData(downloadedKeyBytes);
// verify downloaded key by comparing fingerprints
- if (entry.getFingerPrintHex() != null) {
+ if (entry.getFingerprintHex() != null) {
String downloadedKeyFp = PgpKeyHelper.convertFingerprintToHex(
downloadedKey.getFingerprint());
- if (downloadedKeyFp.equals(entry.getFingerPrintHex())) {
+ if (downloadedKeyFp.equals(entry.getFingerprintHex())) {
Log.d(Constants.TAG, "fingerprint of downloaded key is the same as " +
"the requested fingerprint!");
} else {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java
index bf6abcd6f..e93d717e1 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java
@@ -38,7 +38,7 @@ import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListKeybaseLoader;
import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListLoader;
import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListServerLoader;
import org.sufficientlysecure.keychain.util.InputData;
-import org.sufficientlysecure.keychain.keyimport.KeyServer;
+import org.sufficientlysecure.keychain.keyimport.Keyserver;
import org.sufficientlysecure.keychain.util.Log;
import java.io.ByteArrayInputStream;
@@ -280,13 +280,13 @@ public class ImportKeysListFragment extends ListFragment implements
mAdapter.getCount(), mAdapter.getCount()),
AppMsg.STYLE_INFO
).show();
- } else if (error instanceof KeyServer.InsufficientQuery) {
+ } else if (error instanceof Keyserver.InsufficientQuery) {
AppMsg.makeText(getActivity(), R.string.error_keyserver_insufficient_query,
AppMsg.STYLE_ALERT).show();
- } else if (error instanceof KeyServer.QueryException) {
+ } else if (error instanceof Keyserver.QueryException) {
AppMsg.makeText(getActivity(), R.string.error_keyserver_query,
AppMsg.STYLE_ALERT).show();
- } else if (error instanceof KeyServer.TooManyResponses) {
+ } else if (error instanceof Keyserver.TooManyResponses) {
AppMsg.makeText(getActivity(), R.string.error_keyserver_too_many_responses,
AppMsg.STYLE_ALERT).show();
}
@@ -300,7 +300,7 @@ public class ImportKeysListFragment extends ListFragment implements
mAdapter.getCount(), mAdapter.getCount()),
AppMsg.STYLE_INFO
).show();
- } else if (error instanceof KeyServer.QueryException) {
+ } else if (error instanceof Keyserver.QueryException) {
AppMsg.makeText(getActivity(), R.string.error_keyserver_query,
AppMsg.STYLE_ALERT).show();
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java
index a3f4b0753..9c90b5eb7 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java
@@ -34,6 +34,7 @@ import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.support.v4.view.MenuItemCompat;
import android.support.v7.app.ActionBarActivity;
+import android.support.v4.widget.CursorAdapter;
import android.support.v7.widget.SearchView;
import android.text.TextUtils;
import android.view.ActionMode;
@@ -61,8 +62,8 @@ import org.sufficientlysecure.keychain.helper.ExportHelper;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
-import org.sufficientlysecure.keychain.ui.adapter.HighlightQueryCursorAdapter;
import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment;
+import org.sufficientlysecure.keychain.util.Highlighter;
import org.sufficientlysecure.keychain.util.Log;
import java.util.Date;
@@ -82,7 +83,7 @@ public class KeyListFragment extends LoaderFragment
private KeyListAdapter mAdapter;
private StickyListHeadersListView mStickyList;
- private String mCurQuery;
+ private String mQuery;
private SearchView mSearchView;
// empty list layout
private BootstrapButton mButtonEmptyCreate;
@@ -130,7 +131,7 @@ public class KeyListFragment extends LoaderFragment
/**
* Define Adapter and Loader on create of Activity
*/
- @SuppressLint("NewApi")
+ @TargetApi(Build.VERSION_CODES.HONEYCOMB)
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
@@ -141,8 +142,7 @@ public class KeyListFragment extends LoaderFragment
mStickyList.setFastScrollEnabled(true);
/*
- * ActionBarSherlock does not support MultiChoiceModeListener. Thus multi-selection is only
- * available for Android >= 3.0
+ * Multi-selection is only available for Android >= 3.0
*/
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
mStickyList.setFastScrollAlwaysVisible(true);
@@ -263,9 +263,18 @@ public class KeyListFragment extends LoaderFragment
Uri baseUri = KeyRings.buildUnifiedKeyRingsUri();
String where = null;
String whereArgs[] = null;
- if (mCurQuery != null) {
- where = KeyRings.USER_ID + " LIKE ?";
- whereArgs = new String[]{"%" + mCurQuery + "%"};
+ if (mQuery != null) {
+ String[] words = mQuery.trim().split("\\s+");
+ whereArgs = new String[words.length];
+ for (int i = 0; i < words.length; ++i) {
+ if (where == null) {
+ where = "";
+ } else {
+ where += " AND ";
+ }
+ where += KeyRings.USER_ID + " LIKE ?";
+ whereArgs[i] = "%" + words[i] + "%";
+ }
}
// Now create and return a CursorLoader that will take care of
@@ -277,7 +286,7 @@ public class KeyListFragment extends LoaderFragment
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
// Swap the new cursor in. (The framework will take care of closing the
// old cursor once we return.)
- mAdapter.setSearchQuery(mCurQuery);
+ mAdapter.setSearchQuery(mQuery);
mAdapter.swapCursor(data);
mStickyList.setAdapter(mAdapter);
@@ -312,7 +321,7 @@ public class KeyListFragment extends LoaderFragment
startActivity(viewIntent);
}
- @TargetApi(11)
+ @TargetApi(Build.VERSION_CODES.HONEYCOMB)
protected void encrypt(ActionMode mode, long[] masterKeyIds) {
Intent intent = new Intent(getActivity(), EncryptActivity.class);
intent.setAction(EncryptActivity.ACTION_ENCRYPT);
@@ -329,7 +338,7 @@ public class KeyListFragment extends LoaderFragment
* @param masterKeyIds
* @param hasSecret must contain whether the list of masterKeyIds contains a secret key or not
*/
- @TargetApi(11)
+ @TargetApi(Build.VERSION_CODES.HONEYCOMB)
public void showDeleteKeyDialog(final ActionMode mode, long[] masterKeyIds, boolean hasSecret) {
// Can only work on singular secret keys
if(hasSecret && masterKeyIds.length > 1) {
@@ -379,7 +388,7 @@ public class KeyListFragment extends LoaderFragment
@Override
public boolean onMenuItemActionCollapse(MenuItem item) {
- mCurQuery = null;
+ mQuery = null;
mSearchView.setQuery("", true);
getLoaderManager().restartLoader(0, null, KeyListFragment.this);
return true;
@@ -399,7 +408,7 @@ public class KeyListFragment extends LoaderFragment
// Called when the action bar search text has changed. Update
// the search filter, and restart the loader to do a new query
// with this filter.
- mCurQuery = !TextUtils.isEmpty(s) ? s : null;
+ mQuery = !TextUtils.isEmpty(s) ? s : null;
getLoaderManager().restartLoader(0, null, this);
return true;
}
@@ -407,7 +416,8 @@ public class KeyListFragment extends LoaderFragment
/**
* Implements StickyListHeadersAdapter from library
*/
- private class KeyListAdapter extends HighlightQueryCursorAdapter implements StickyListHeadersAdapter {
+ private class KeyListAdapter extends CursorAdapter implements StickyListHeadersAdapter {
+ private String mQuery;
private LayoutInflater mInflater;
private HashMap<Integer, Boolean> mSelection = new HashMap<Integer, Boolean>();
@@ -418,6 +428,10 @@ public class KeyListFragment extends LoaderFragment
mInflater = LayoutInflater.from(context);
}
+ public void setSearchQuery(String query) {
+ mQuery = query;
+ }
+
@Override
public Cursor swapCursor(Cursor newCursor) {
return super.swapCursor(newCursor);
@@ -456,18 +470,19 @@ public class KeyListFragment extends LoaderFragment
*/
@Override
public void bindView(View view, Context context, Cursor cursor) {
+ Highlighter highlighter = new Highlighter(context, mQuery);
ItemViewHolder h = (ItemViewHolder) view.getTag();
{ // set name and stuff, common to both key types
String userId = cursor.getString(INDEX_USER_ID);
String[] userIdSplit = PgpKeyHelper.splitUserId(userId);
if (userIdSplit[0] != null) {
- h.mMainUserId.setText(highlightSearchQuery(userIdSplit[0]));
+ h.mMainUserId.setText(highlighter.highlight(userIdSplit[0]));
} else {
h.mMainUserId.setText(R.string.user_id_no_name);
}
if (userIdSplit[1] != null) {
- h.mMainUserIdRest.setText(highlightSearchQuery(userIdSplit[1]));
+ h.mMainUserIdRest.setText(highlighter.highlight(userIdSplit[1]));
h.mMainUserIdRest.setVisibility(View.VISIBLE);
} else {
h.mMainUserIdRest.setVisibility(View.GONE);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyFragment.java
index 2ad769b00..9343b166a 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyFragment.java
@@ -55,7 +55,7 @@ public class SelectPublicKeyFragment extends ListFragmentWorkaround implements T
private SelectKeyCursorAdapter mAdapter;
private EditText mSearchView;
private long mSelectedMasterKeyIds[];
- private String mCurQuery;
+ private String mQuery;
// copied from ListFragment
static final int INTERNAL_EMPTY_ID = 0x00ff0001;
@@ -281,9 +281,18 @@ public class SelectPublicKeyFragment extends ListFragmentWorkaround implements T
}
String where = null;
String whereArgs[] = null;
- if (mCurQuery != null) {
- where = KeyRings.USER_ID + " LIKE ?";
- whereArgs = new String[]{"%" + mCurQuery + "%"};
+ if (mQuery != null) {
+ String[] words = mQuery.trim().split("\\s+");
+ whereArgs = new String[words.length];
+ for (int i = 0; i < words.length; ++i) {
+ if (where == null) {
+ where = "";
+ } else {
+ where += " AND ";
+ }
+ where += KeyRings.USER_ID + " LIKE ?";
+ whereArgs[i] = "%" + words[i] + "%";
+ }
}
// Now create and return a CursorLoader that will take care of
@@ -295,7 +304,7 @@ public class SelectPublicKeyFragment extends ListFragmentWorkaround implements T
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
// Swap the new cursor in. (The framework will take care of closing the
// old cursor once we return.)
- mAdapter.setSearchQuery(mCurQuery);
+ mAdapter.setSearchQuery(mQuery);
mAdapter.swapCursor(data);
// The list should now be shown.
@@ -329,7 +338,7 @@ public class SelectPublicKeyFragment extends ListFragmentWorkaround implements T
@Override
public void afterTextChanged(Editable editable) {
- mCurQuery = !TextUtils.isEmpty(editable.toString()) ? editable.toString() : null;
+ mQuery = !TextUtils.isEmpty(editable.toString()) ? editable.toString() : null;
getLoaderManager().restartLoader(0, null, this);
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/HighlightQueryCursorAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/HighlightQueryCursorAdapter.java
deleted file mode 100644
index fd7a2dc30..000000000
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/HighlightQueryCursorAdapter.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package org.sufficientlysecure.keychain.ui.adapter;
-
-import android.content.Context;
-import android.database.Cursor;
-import android.support.v4.widget.CursorAdapter;
-import android.text.Spannable;
-import android.text.style.ForegroundColorSpan;
-
-import org.sufficientlysecure.keychain.R;
-
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-public abstract class HighlightQueryCursorAdapter extends CursorAdapter {
-
- private String mCurQuery;
-
- public HighlightQueryCursorAdapter(Context context, Cursor c, int flags) {
- super(context, c, flags);
- mCurQuery = null;
- }
-
- public void setSearchQuery(String searchQuery) {
- mCurQuery = searchQuery;
- }
-
- public String getSearchQuery() {
- return mCurQuery;
- }
-
- protected Spannable highlightSearchQuery(String text) {
- Spannable highlight = Spannable.Factory.getInstance().newSpannable(text);
-
- if (mCurQuery != null) {
- Pattern pattern = Pattern.compile("(?i)" + mCurQuery);
- Matcher matcher = pattern.matcher(text);
- if (matcher.find()) {
- highlight.setSpan(
- new ForegroundColorSpan(mContext.getResources().getColor(R.color.emphasis)),
- matcher.start(),
- matcher.end(),
- Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
- }
- return highlight;
- } else {
- return highlight;
- }
- }
-}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java
index 9d323c822..9573efdfe 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java
@@ -33,6 +33,7 @@ import android.widget.TextView;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.keyimport.ImportKeysListEntry;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
+import org.sufficientlysecure.keychain.util.Highlighter;
import java.util.ArrayList;
import java.util.Iterator;
@@ -99,6 +100,7 @@ public class ImportKeysAdapter extends ArrayAdapter<ImportKeysListEntry> {
public View getView(int position, View convertView, ViewGroup parent) {
ImportKeysListEntry entry = mData.get(position);
+ Highlighter highlighter = new Highlighter(mActivity, entry.getQuery());
ViewHolder holder;
if (convertView == null) {
holder = new ViewHolder();
@@ -128,7 +130,7 @@ public class ImportKeysAdapter extends ArrayAdapter<ImportKeysListEntry> {
+ " " + userIdSplit[0]);
holder.mainUserId.setTextColor(Color.RED);
} else {
- holder.mainUserId.setText(userIdSplit[0]);
+ holder.mainUserId.setText(highlighter.highlight(userIdSplit[0]));
holder.mainUserId.setTextColor(Color.BLACK);
}
} else {
@@ -139,21 +141,26 @@ public class ImportKeysAdapter extends ArrayAdapter<ImportKeysListEntry> {
// email
if (userIdSplit[1] != null) {
holder.mainUserIdRest.setVisibility(View.VISIBLE);
- holder.mainUserIdRest.setText(userIdSplit[1]);
+ holder.mainUserIdRest.setText(highlighter.highlight(userIdSplit[1]));
} else {
holder.mainUserIdRest.setVisibility(View.GONE);
}
holder.keyId.setText(entry.keyIdHex);
- if (entry.fingerPrintHex != null) {
+ if (entry.fingerprintHex != null) {
holder.fingerprint.setVisibility(View.VISIBLE);
- holder.fingerprint.setText(PgpKeyHelper.colorizeFingerprint(entry.fingerPrintHex));
+ holder.fingerprint.setText(PgpKeyHelper.colorizeFingerprint(entry.fingerprintHex));
} else {
holder.fingerprint.setVisibility(View.GONE);
}
- holder.algorithm.setText("" + entry.bitStrength + "/" + entry.algorithm);
+ if (entry.bitStrength != 0 && entry.algorithm != null) {
+ holder.algorithm.setText("" + entry.bitStrength + "/" + entry.algorithm);
+ holder.algorithm.setVisibility(View.VISIBLE);
+ } else {
+ holder.algorithm.setVisibility(View.INVISIBLE);
+ }
if (entry.revoked) {
holder.status.setVisibility(View.VISIBLE);
@@ -177,7 +184,7 @@ public class ImportKeysAdapter extends ArrayAdapter<ImportKeysListEntry> {
String uid = it.next();
TextView uidView = (TextView) mInflater.inflate(
R.layout.import_keys_list_entry_user_id, null);
- uidView.setText(uid);
+ uidView.setText(highlighter.highlight(uid));
holder.userIdsList.addView(uidView);
}
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListKeybaseLoader.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListKeybaseLoader.java
index 420880522..0fdc019d0 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListKeybaseLoader.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListKeybaseLoader.java
@@ -22,8 +22,8 @@ import android.support.v4.content.AsyncTaskLoader;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.keyimport.ImportKeysListEntry;
-import org.sufficientlysecure.keychain.keyimport.KeyServer;
-import org.sufficientlysecure.keychain.keyimport.KeybaseKeyServer;
+import org.sufficientlysecure.keychain.keyimport.Keyserver;
+import org.sufficientlysecure.keychain.keyimport.KeybaseKeyserver;
import org.sufficientlysecure.keychain.util.Log;
import java.util.ArrayList;
@@ -86,7 +86,7 @@ public class ImportKeysListKeybaseLoader
*/
private void queryServer(String query) {
- KeybaseKeyServer server = new KeybaseKeyServer();
+ KeybaseKeyserver server = new KeybaseKeyserver();
try {
ArrayList<ImportKeysListEntry> searchResult = server.search(query);
@@ -94,11 +94,11 @@ public class ImportKeysListKeybaseLoader
mEntryList.addAll(searchResult);
mEntryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(mEntryList, null);
- } catch (KeyServer.InsufficientQuery e) {
+ } catch (Keyserver.InsufficientQuery e) {
mEntryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(mEntryList, e);
- } catch (KeyServer.QueryException e) {
+ } catch (Keyserver.QueryException e) {
mEntryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(mEntryList, e);
- } catch (KeyServer.TooManyResponses e) {
+ } catch (Keyserver.TooManyResponses e) {
mEntryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(mEntryList, e);
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListServerLoader.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListServerLoader.java
index 4175592d6..1b8d7d30e 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListServerLoader.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListServerLoader.java
@@ -21,9 +21,9 @@ import android.content.Context;
import android.support.v4.content.AsyncTaskLoader;
import org.sufficientlysecure.keychain.Constants;
-import org.sufficientlysecure.keychain.keyimport.HkpKeyServer;
+import org.sufficientlysecure.keychain.keyimport.HkpKeyserver;
import org.sufficientlysecure.keychain.keyimport.ImportKeysListEntry;
-import org.sufficientlysecure.keychain.keyimport.KeyServer;
+import org.sufficientlysecure.keychain.keyimport.Keyserver;
import org.sufficientlysecure.keychain.util.Log;
import java.util.ArrayList;
@@ -92,7 +92,7 @@ public class ImportKeysListServerLoader
* Query keyserver
*/
private void queryServer(String query, String keyServer, boolean enforceFingerprint) {
- HkpKeyServer server = new HkpKeyServer(keyServer);
+ HkpKeyserver server = new HkpKeyserver(keyServer);
try {
ArrayList<ImportKeysListEntry> searchResult = server.search(query);
@@ -108,7 +108,7 @@ public class ImportKeysListServerLoader
* set fingerprint explicitly after query
* to enforce a check when the key is imported by KeychainIntentService
*/
- uniqueEntry.setFingerPrintHex(fingerprint);
+ uniqueEntry.setFingerprintHex(fingerprint);
uniqueEntry.setSelected(true);
mEntryList.add(uniqueEntry);
}
@@ -116,11 +116,11 @@ public class ImportKeysListServerLoader
mEntryList.addAll(searchResult);
}
mEntryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(mEntryList, null);
- } catch (KeyServer.InsufficientQuery e) {
+ } catch (Keyserver.InsufficientQuery e) {
mEntryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(mEntryList, e);
- } catch (KeyServer.QueryException e) {
+ } catch (Keyserver.QueryException e) {
mEntryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(mEntryList, e);
- } catch (KeyServer.TooManyResponses e) {
+ } catch (Keyserver.TooManyResponses e) {
mEntryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(mEntryList, e);
}
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SelectKeyCursorAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SelectKeyCursorAdapter.java
index cde008175..00cd554b9 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SelectKeyCursorAdapter.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SelectKeyCursorAdapter.java
@@ -19,6 +19,7 @@ package org.sufficientlysecure.keychain.ui.adapter;
import android.content.Context;
import android.database.Cursor;
+import android.support.v4.widget.CursorAdapter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -29,6 +30,7 @@ import android.widget.TextView;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
+import org.sufficientlysecure.keychain.util.Highlighter;
import java.util.Date;
@@ -36,8 +38,9 @@ import java.util.Date;
/**
* Yes this class is abstract!
*/
-abstract public class SelectKeyCursorAdapter extends HighlightQueryCursorAdapter {
+abstract public class SelectKeyCursorAdapter extends CursorAdapter {
+ private String mQuery;
private LayoutInflater mInflater;
protected int mIndexUserId, mIndexMasterKeyId, mIndexRevoked, mIndexExpiry;
@@ -48,6 +51,10 @@ abstract public class SelectKeyCursorAdapter extends HighlightQueryCursorAdapter
initIndex(c);
}
+ public void setSearchQuery(String query) {
+ mQuery = query;
+ }
+
@Override
public Cursor swapCursor(Cursor newCursor) {
initIndex(newCursor);
@@ -101,19 +108,20 @@ abstract public class SelectKeyCursorAdapter extends HighlightQueryCursorAdapter
@Override
public void bindView(View view, Context context, Cursor cursor) {
+ Highlighter highlighter = new Highlighter(context, mQuery);
ViewHolderItem h = (ViewHolderItem) view.getTag();
String userId = cursor.getString(mIndexUserId);
String[] userIdSplit = PgpKeyHelper.splitUserId(userId);
if (userIdSplit[0] != null) {
- h.mainUserId.setText(highlightSearchQuery(userIdSplit[0]));
+ h.mainUserId.setText(highlighter.highlight(userIdSplit[0]));
} else {
h.mainUserId.setText(R.string.user_id_no_name);
}
if (userIdSplit[1] != null) {
h.mainUserIdRest.setVisibility(View.VISIBLE);
- h.mainUserIdRest.setText(highlightSearchQuery(userIdSplit[1]));
+ h.mainUserIdRest.setText(highlighter.highlight(userIdSplit[1]));
} else {
h.mainUserIdRest.setVisibility(View.GONE);
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Highlighter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Highlighter.java
new file mode 100644
index 000000000..eeeacf465
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Highlighter.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2014 Thialfihar <thi@thialfihar.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package org.sufficientlysecure.keychain.util;
+
+import android.content.Context;
+import android.text.Spannable;
+import android.text.style.ForegroundColorSpan;
+
+import org.sufficientlysecure.keychain.R;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class Highlighter {
+ private Context mContext;
+ private String mQuery;
+
+ public Highlighter(Context context, String query) {
+ mContext = context;
+ mQuery = query;
+ }
+
+ public Spannable highlight(String text) {
+ Spannable highlight = Spannable.Factory.getInstance().newSpannable(text);
+
+ if (mQuery == null) {
+ return highlight;
+ }
+
+ Pattern pattern = Pattern.compile("(?i)(" + mQuery.trim().replaceAll("\\s+", "|") + ")");
+ Matcher matcher = pattern.matcher(text);
+ while (matcher.find()) {
+ highlight.setSpan(
+ new ForegroundColorSpan(mContext.getResources().getColor(R.color.emphasis)),
+ matcher.start(),
+ matcher.end(),
+ Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ }
+
+ return highlight;
+ }
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/JWalk.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/JWalk.java
index 7ae1d8fab..76797811d 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/JWalk.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/JWalk.java
@@ -23,29 +23,77 @@ import org.json.JSONObject;
/**
* Minimal hierarchy selector
+ *
+ * This is for picking out an item in a large multilevel JSON object, for example look at
+ * the Keybase.io User object, documentation at https://keybase.io/__/api-docs/1.0#user-objects
+ * an example available via
+ * curl https://keybase.io/_/api/1.0/user/lookup.json?username=timbray
+ *
+ * If you want to retrieve the ascii-armored key, you'd say
+ * String key = JWalk.getString(match,"them", "public_keys", "primary", "bundle");
*/
public class JWalk {
+ /**
+ * Returns an int member value from the JSON sub-object addressed by the path
+ *
+ * @param json The object
+ * @param path list of string object member selectors
+ * @return the int addressed by the path, assuming such a thing exists
+ * @throws JSONException if any step in the path doesn’t work
+ */
public static int getInt(JSONObject json, String... path) throws JSONException {
json = walk(json, path);
return json.getInt(path[path.length - 1]);
}
+ /**
+ * Returns a long member value from the JSON sub-object addressed by the path
+ *
+ * @param json The object
+ * @param path list of string object member selectors
+ * @return the int addressed by the path, assuming such a thing exists
+ * @throws JSONException if any step in the path doesn’t work
+ */
public static long getLong(JSONObject json, String... path) throws JSONException {
json = walk(json, path);
return json.getLong(path[path.length - 1]);
}
+ /**
+ * Returns a String member value from the JSON sub-object addressed by the path
+ *
+ * @param json The object
+ * @param path list of string object member selectors
+ * @return the int addressed by the path, assuming such a thing exists
+ * @throws JSONException if any step in the path doesn’t work
+ */
public static String getString(JSONObject json, String... path) throws JSONException {
json = walk(json, path);
return json.getString(path[path.length - 1]);
}
+ /**
+ * Returns a JSONArray member value from the JSON sub-object addressed by the path
+ *
+ * @param json The object
+ * @param path list of string object member selectors
+ * @return the int addressed by the path, assuming such a thing exists
+ * @throws JSONException if any step in the path doesn’t work
+ */
public static JSONArray getArray(JSONObject json, String... path) throws JSONException {
json = walk(json, path);
return json.getJSONArray(path[path.length - 1]);
}
+ /**
+ * Returns a JSONObject member value from the JSON sub-object addressed by the path, or null
+ *
+ * @param json The object
+ * @param path list of string object member selectors
+ * @return the int addressed by the path, assuming such a thing exists
+ * @throws JSONException if any step in the path, except for the last, doesn’t work
+ */
public static JSONObject optObject(JSONObject json, String... path) throws JSONException {
json = walk(json, path);
return json.optJSONObject(path[path.length - 1]);