mirror of
https://github.com/moparisthebest/open-keychain
synced 2025-02-24 07:21:49 -05:00
do a TON of UI work
This commit is contained in:
parent
8222315dbd
commit
1f324be243
@ -114,6 +114,15 @@ public class WrappedUserAttribute implements Serializable {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public byte[][] getSubpackets() {
|
||||||
|
UserAttributeSubpacket[] subpackets = mVector.toSubpacketArray();
|
||||||
|
byte[][] ret = new byte[subpackets.length][];
|
||||||
|
for (int i = 0; i < subpackets.length; i++) {
|
||||||
|
ret[i] = subpackets[i].getData();
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
private void readObjectNoData() throws ObjectStreamException {
|
private void readObjectNoData() throws ObjectStreamException {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,27 +19,10 @@ import java.util.Set;
|
|||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
public abstract class LinkedCookieResource {
|
public abstract class LinkedCookieResource extends LinkedResource {
|
||||||
|
|
||||||
protected final URI mSubUri;
|
|
||||||
protected final Set<String> mFlags;
|
|
||||||
protected final HashMap<String,String> mParams;
|
|
||||||
|
|
||||||
static Pattern magicPattern =
|
|
||||||
Pattern.compile("\\[Verifying my PGP key: openpgp4fpr:([a-zA-Z0-9]+)#([a-zA-Z0-9]+)\\]");
|
|
||||||
|
|
||||||
protected LinkedCookieResource(Set<String> flags, HashMap<String, String> params, URI uri) {
|
protected LinkedCookieResource(Set<String> flags, HashMap<String, String> params, URI uri) {
|
||||||
mFlags = flags;
|
super(flags, params, uri);
|
||||||
mParams = params;
|
|
||||||
mSubUri = uri;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<String> getFlags () {
|
|
||||||
return new HashSet<String>(mFlags);
|
|
||||||
}
|
|
||||||
|
|
||||||
public HashMap<String,String> getParams () {
|
|
||||||
return new HashMap<String,String>(mParams);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public URI toUri () {
|
public URI toUri () {
|
||||||
@ -82,10 +65,10 @@ public abstract class LinkedCookieResource {
|
|||||||
return mSubUri;
|
return mSubUri;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String generate (Context context, byte[] fingerprint, String nonce) {
|
public static String generate (Context context, byte[] fingerprint, int nonce) {
|
||||||
|
|
||||||
return "[Verifying my PGP key: openpgp4fpr:"
|
return "[Verifying my PGP key: openpgp4fpr:"
|
||||||
+ KeyFormattingUtils.convertFingerprintToHex(fingerprint) + "#" + nonce + "]";
|
+ KeyFormattingUtils.convertFingerprintToHex(fingerprint) + "#" + Integer.toHexString(nonce) + "]";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,7 +112,17 @@ public abstract class LinkedCookieResource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String candidateFp = match.group(1).toLowerCase();
|
String candidateFp = match.group(1).toLowerCase();
|
||||||
int nonceCandidate = Integer.parseInt(match.group(2).toLowerCase(), 16);
|
try {
|
||||||
|
int nonceCandidate = Integer.parseInt(match.group(2).toLowerCase(), 16);
|
||||||
|
|
||||||
|
if (nonce != nonceCandidate) {
|
||||||
|
log.add(LogType.MSG_LV_NONCE_ERROR, indent);
|
||||||
|
return new LinkedVerifyResult(LinkedVerifyResult.RESULT_ERROR, log);
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
log.add(LogType.MSG_LV_NONCE_ERROR, indent);
|
||||||
|
return new LinkedVerifyResult(LinkedVerifyResult.RESULT_ERROR, log);
|
||||||
|
}
|
||||||
|
|
||||||
String fp = KeyFormattingUtils.convertFingerprintToHex(fingerprint);
|
String fp = KeyFormattingUtils.convertFingerprintToHex(fingerprint);
|
||||||
|
|
||||||
@ -139,72 +132,9 @@ public abstract class LinkedCookieResource {
|
|||||||
}
|
}
|
||||||
log.add(LogType.MSG_LV_FP_OK, indent);
|
log.add(LogType.MSG_LV_FP_OK, indent);
|
||||||
|
|
||||||
if (nonce != nonceCandidate) {
|
|
||||||
log.add(LogType.MSG_LV_NONCE_ERROR, indent);
|
|
||||||
return new LinkedVerifyResult(LinkedVerifyResult.RESULT_ERROR, log);
|
|
||||||
}
|
|
||||||
|
|
||||||
log.add(LogType.MSG_LV_NONCE_OK, indent);
|
log.add(LogType.MSG_LV_NONCE_OK, indent);
|
||||||
return new LinkedVerifyResult(LinkedVerifyResult.RESULT_OK, log);
|
return new LinkedVerifyResult(LinkedVerifyResult.RESULT_OK, log);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static LinkedCookieResource fromRawLinkedId (RawLinkedIdentity id) {
|
|
||||||
return fromUri(id.mNonce, id.mUri);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static LinkedCookieResource fromUri (int nonce, URI uri) {
|
|
||||||
|
|
||||||
if ("pgpid".equals(uri.getScheme())) {
|
|
||||||
Log.e(Constants.TAG, "unknown uri scheme in (suspected) linked id packet");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!uri.isOpaque()) {
|
|
||||||
Log.e(Constants.TAG, "non-opaque uri in (suspected) linked id packet");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
String specific = uri.getSchemeSpecificPart();
|
|
||||||
if (!specific.contains("@")) {
|
|
||||||
Log.e(Constants.TAG, "unknown uri scheme in linked id packet");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
String[] pieces = specific.split("@", 2);
|
|
||||||
URI subUri = URI.create(pieces[1]);
|
|
||||||
|
|
||||||
Set<String> flags = new HashSet<String>();
|
|
||||||
HashMap<String,String> params = new HashMap<String,String>();
|
|
||||||
{
|
|
||||||
String[] rawParams = pieces[0].split(";");
|
|
||||||
for (String param : rawParams) {
|
|
||||||
String[] p = param.split("=", 2);
|
|
||||||
if (p.length == 1) {
|
|
||||||
flags.add(param);
|
|
||||||
} else {
|
|
||||||
params.put(p[0], p[1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return findResourceType(nonce, flags, params, subUri);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static LinkedCookieResource findResourceType (int nonce, Set<String> flags,
|
|
||||||
HashMap<String,String> params,
|
|
||||||
URI subUri) {
|
|
||||||
|
|
||||||
LinkedCookieResource res;
|
|
||||||
|
|
||||||
res = GenericHttpsResource.create(flags, params, subUri);
|
|
||||||
if (res != null) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new UnknownResource(flags, params, subUri);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,75 @@
|
|||||||
|
package org.sufficientlysecure.keychain.pgp.linked;
|
||||||
|
|
||||||
|
import org.spongycastle.bcpg.UserAttributeSubpacket;
|
||||||
|
import org.spongycastle.util.Strings;
|
||||||
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
|
import org.sufficientlysecure.keychain.pgp.WrappedUserAttribute;
|
||||||
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
public class LinkedIdentity extends RawLinkedIdentity {
|
||||||
|
|
||||||
|
public final LinkedResource mResource;
|
||||||
|
|
||||||
|
protected LinkedIdentity(int nonce, URI uri, LinkedResource resource) {
|
||||||
|
super(nonce, uri);
|
||||||
|
if (resource == null) {
|
||||||
|
throw new AssertionError("resource must not be null in a LinkedIdentity!");
|
||||||
|
}
|
||||||
|
mResource = resource;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static RawLinkedIdentity fromAttributeData(byte[] data) throws IOException {
|
||||||
|
WrappedUserAttribute att = WrappedUserAttribute.fromData(data);
|
||||||
|
|
||||||
|
byte[][] subpackets = att.getSubpackets();
|
||||||
|
if (subpackets.length >= 1) {
|
||||||
|
return fromSubpacketData(subpackets[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IOException("no subpacket data");
|
||||||
|
}
|
||||||
|
|
||||||
|
/** This method parses a linked id from a UserAttributeSubpacket, or returns null if the
|
||||||
|
* subpacket can not be parsed as a valid linked id.
|
||||||
|
*/
|
||||||
|
static RawLinkedIdentity fromAttributeSubpacket(UserAttributeSubpacket subpacket) {
|
||||||
|
if (subpacket.getType() != 100) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] data = subpacket.getData();
|
||||||
|
|
||||||
|
return fromSubpacketData(data);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static RawLinkedIdentity fromSubpacketData(byte[] data) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
int nonce = ByteBuffer.wrap(data).getInt();
|
||||||
|
String uriStr = Strings.fromUTF8ByteArray(Arrays.copyOfRange(data, 4, data.length));
|
||||||
|
URI uri = URI.create(uriStr);
|
||||||
|
|
||||||
|
LinkedResource res = LinkedResource.fromUri(uri);
|
||||||
|
if (res == null) {
|
||||||
|
return new RawLinkedIdentity(nonce, uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new LinkedIdentity(nonce, uri, res);
|
||||||
|
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
Log.e(Constants.TAG, "error parsing uri in (suspected) linked id packet");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static RawLinkedIdentity fromResource (LinkedCookieResource res, int nonce) {
|
||||||
|
return new RawLinkedIdentity(nonce, res.toUri());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,101 @@
|
|||||||
|
package org.sufficientlysecure.keychain.pgp.linked;
|
||||||
|
|
||||||
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
|
import org.sufficientlysecure.keychain.pgp.linked.resources.DnsResource;
|
||||||
|
import org.sufficientlysecure.keychain.pgp.linked.resources.GenericHttpsResource;
|
||||||
|
import org.sufficientlysecure.keychain.pgp.linked.resources.UnknownResource;
|
||||||
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
public abstract class LinkedResource {
|
||||||
|
|
||||||
|
protected final URI mSubUri;
|
||||||
|
protected final Set<String> mFlags;
|
||||||
|
protected final HashMap<String,String> mParams;
|
||||||
|
|
||||||
|
static Pattern magicPattern =
|
||||||
|
Pattern.compile("\\[Verifying my PGP key: openpgp4fpr:([a-zA-Z0-9]+)#([a-zA-Z0-9]+)\\]");
|
||||||
|
|
||||||
|
protected LinkedResource(Set<String> flags, HashMap<String, String> params, URI uri) {
|
||||||
|
mFlags = flags;
|
||||||
|
mParams = params;
|
||||||
|
mSubUri = uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract URI toUri();
|
||||||
|
|
||||||
|
public Set<String> getFlags () {
|
||||||
|
return new HashSet<>(mFlags);
|
||||||
|
}
|
||||||
|
|
||||||
|
public HashMap<String,String> getParams () {
|
||||||
|
return new HashMap<>(mParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static LinkedCookieResource fromUri (URI uri) {
|
||||||
|
|
||||||
|
if ("pgpid+cookie".equals(uri.getScheme())) {
|
||||||
|
Log.e(Constants.TAG, "unknown uri scheme in (suspected) linked id packet");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!uri.isOpaque()) {
|
||||||
|
Log.e(Constants.TAG, "non-opaque uri in (suspected) linked id packet");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
String specific = uri.getSchemeSpecificPart();
|
||||||
|
if (!specific.contains("@")) {
|
||||||
|
Log.e(Constants.TAG, "unknown uri scheme in linked id packet");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
String[] pieces = specific.split("@", 2);
|
||||||
|
URI subUri = URI.create(pieces[1]);
|
||||||
|
|
||||||
|
Set<String> flags = new HashSet<String>();
|
||||||
|
HashMap<String,String> params = new HashMap<String,String>();
|
||||||
|
{
|
||||||
|
String[] rawParams = pieces[0].split(";");
|
||||||
|
for (String param : rawParams) {
|
||||||
|
String[] p = param.split("=", 2);
|
||||||
|
if ("".equals(p[0])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (p.length == 1) {
|
||||||
|
flags.add(param);
|
||||||
|
} else {
|
||||||
|
params.put(p[0], p[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return findResourceType(flags, params, subUri);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static LinkedCookieResource findResourceType (Set<String> flags,
|
||||||
|
HashMap<String,String> params,
|
||||||
|
URI subUri) {
|
||||||
|
|
||||||
|
LinkedCookieResource res;
|
||||||
|
|
||||||
|
res = GenericHttpsResource.create(flags, params, subUri);
|
||||||
|
if (res != null) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
res = DnsResource.create(flags, params, subUri);
|
||||||
|
if (res != null) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,18 +1,10 @@
|
|||||||
package org.sufficientlysecure.keychain.pgp.linked;
|
package org.sufficientlysecure.keychain.pgp.linked;
|
||||||
|
|
||||||
import org.spongycastle.bcpg.UserAttributeSubpacket;
|
|
||||||
import org.spongycastle.util.Strings;
|
import org.spongycastle.util.Strings;
|
||||||
import org.sufficientlysecure.keychain.Constants;
|
|
||||||
import org.sufficientlysecure.keychain.pgp.WrappedUserAttribute;
|
import org.sufficientlysecure.keychain.pgp.WrappedUserAttribute;
|
||||||
import org.sufficientlysecure.keychain.util.Log;
|
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Map.Entry;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/** The RawLinkedIdentity contains raw parsed data from a Linked Identity subpacket. */
|
/** The RawLinkedIdentity contains raw parsed data from a Linked Identity subpacket. */
|
||||||
public class RawLinkedIdentity {
|
public class RawLinkedIdentity {
|
||||||
@ -36,50 +28,18 @@ public class RawLinkedIdentity {
|
|||||||
return buf.array();
|
return buf.array();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** This method parses a linked id from a UserAttributeSubpacket, or returns null if the
|
|
||||||
* subpacket can not be parsed as a valid linked id.
|
|
||||||
*/
|
|
||||||
static RawLinkedIdentity fromAttributeSubpacket(UserAttributeSubpacket subpacket) {
|
|
||||||
if (subpacket.getType() != 100) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] data = subpacket.getData();
|
|
||||||
|
|
||||||
return fromSubpacketData(data);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static RawLinkedIdentity fromSubpacketData(byte[] data) {
|
|
||||||
|
|
||||||
try {
|
|
||||||
int nonce = ByteBuffer.wrap(data).getInt();
|
|
||||||
String uri = Strings.fromUTF8ByteArray(Arrays.copyOfRange(data, 4, data.length));
|
|
||||||
|
|
||||||
return new RawLinkedIdentity(nonce, URI.create(uri));
|
|
||||||
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
Log.e(Constants.TAG, "error parsing uri in (suspected) linked id packet");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static RawLinkedIdentity fromResource (LinkedCookieResource res, int nonce) {
|
|
||||||
return new RawLinkedIdentity(nonce, res.toUri());
|
|
||||||
}
|
|
||||||
|
|
||||||
public WrappedUserAttribute toUserAttribute () {
|
public WrappedUserAttribute toUserAttribute () {
|
||||||
return WrappedUserAttribute.fromSubpacket(WrappedUserAttribute.UAT_LINKED_ID, getEncoded());
|
return WrappedUserAttribute.fromSubpacket(WrappedUserAttribute.UAT_LINKED_ID, getEncoded());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String generateNonce() {
|
public static int generateNonce() {
|
||||||
// TODO make this actually random
|
// TODO make this actually random
|
||||||
// byte[] data = new byte[4];
|
// byte[] data = new byte[4];
|
||||||
// new SecureRandom().nextBytes(data);
|
// new SecureRandom().nextBytes(data);
|
||||||
// return Hex.toHexString(data);
|
// return Hex.toHexString(data);
|
||||||
|
|
||||||
// debug for now
|
// debug for now
|
||||||
return "01234567";
|
return 1234567;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -39,10 +39,11 @@ public class DnsResource extends LinkedCookieResource {
|
|||||||
mType = type;
|
mType = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String generateText (Context context, byte[] fingerprint, String nonce) {
|
public static String generateText (Context context, byte[] fingerprint, int nonce) {
|
||||||
|
|
||||||
return "pgpid+cookie="
|
return "pgpid+cookie="
|
||||||
+ KeyFormattingUtils.convertFingerprintToHex(fingerprint) + ";" + nonce + "";
|
+ KeyFormattingUtils.convertFingerprintToHex(fingerprint) + ";"
|
||||||
|
+ Integer.toHexString(nonce) + "";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,6 +82,10 @@ public class DnsResource extends LinkedCookieResource {
|
|||||||
return new DnsResource(flags, params, uri, fqdn, clazz, type);
|
return new DnsResource(flags, params, uri, fqdn, clazz, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getFqdn() {
|
||||||
|
return mFqdn;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String fetchResource (OperationLog log, int indent) {
|
protected String fetchResource (OperationLog log, int indent) {
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ public class GenericHttpsResource extends LinkedCookieResource {
|
|||||||
super(flags, params, uri);
|
super(flags, params, uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String generateText (Context context, byte[] fingerprint, String nonce) {
|
public static String generateText (Context context, byte[] fingerprint, int nonce) {
|
||||||
String cookie = LinkedCookieResource.generate(context, fingerprint, nonce);
|
String cookie = LinkedCookieResource.generate(context, fingerprint, nonce);
|
||||||
|
|
||||||
return String.format(context.getResources().getString(R.string.linked_id_generic_text),
|
return String.format(context.getResources().getString(R.string.linked_id_generic_text),
|
||||||
|
@ -35,7 +35,7 @@ public class TwitterResource extends LinkedCookieResource {
|
|||||||
super(flags, params, uri);
|
super(flags, params, uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String generateText (Context context, byte[] fingerprint, String nonce) {
|
public static String generateText (Context context, byte[] fingerprint, int nonce) {
|
||||||
// nothing special here for now, might change this later
|
// nothing special here for now, might change this later
|
||||||
return LinkedCookieResource.generate(context, fingerprint, nonce);
|
return LinkedCookieResource.generate(context, fingerprint, nonce);
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,7 @@ import java.io.IOException;
|
|||||||
*/
|
*/
|
||||||
public class KeychainDatabase extends SQLiteOpenHelper {
|
public class KeychainDatabase extends SQLiteOpenHelper {
|
||||||
private static final String DATABASE_NAME = "openkeychain.db";
|
private static final String DATABASE_NAME = "openkeychain.db";
|
||||||
private static final int DATABASE_VERSION = 8;
|
private static final int DATABASE_VERSION = 9;
|
||||||
static Boolean apgHack = false;
|
static Boolean apgHack = false;
|
||||||
private Context mContext;
|
private Context mContext;
|
||||||
|
|
||||||
@ -61,7 +61,7 @@ public class KeychainDatabase extends SQLiteOpenHelper {
|
|||||||
String KEY_RINGS_PUBLIC = "keyrings_public";
|
String KEY_RINGS_PUBLIC = "keyrings_public";
|
||||||
String KEY_RINGS_SECRET = "keyrings_secret";
|
String KEY_RINGS_SECRET = "keyrings_secret";
|
||||||
String KEYS = "keys";
|
String KEYS = "keys";
|
||||||
String USER_PACKETS = "user_ids";
|
String USER_PACKETS = "user_packets";
|
||||||
String CERTS = "certs";
|
String CERTS = "certs";
|
||||||
String API_APPS = "api_apps";
|
String API_APPS = "api_apps";
|
||||||
String API_ACCOUNTS = "api_accounts";
|
String API_ACCOUNTS = "api_accounts";
|
||||||
@ -119,8 +119,7 @@ public class KeychainDatabase extends SQLiteOpenHelper {
|
|||||||
+ UserPacketsColumns.IS_REVOKED + " INTEGER, "
|
+ UserPacketsColumns.IS_REVOKED + " INTEGER, "
|
||||||
+ UserPacketsColumns.RANK+ " INTEGER, "
|
+ UserPacketsColumns.RANK+ " INTEGER, "
|
||||||
|
|
||||||
+ "PRIMARY KEY(" + UserPacketsColumns.MASTER_KEY_ID + ", " + UserPacketsColumns.USER_ID + "), "
|
+ "PRIMARY KEY(" + UserPacketsColumns.MASTER_KEY_ID + ", " + UserPacketsColumns.RANK + "), "
|
||||||
+ "UNIQUE (" + UserPacketsColumns.MASTER_KEY_ID + ", " + UserPacketsColumns.RANK + "), "
|
|
||||||
+ "FOREIGN KEY(" + UserPacketsColumns.MASTER_KEY_ID + ") REFERENCES "
|
+ "FOREIGN KEY(" + UserPacketsColumns.MASTER_KEY_ID + ") REFERENCES "
|
||||||
+ Tables.KEY_RINGS_PUBLIC + "(" + KeyRingsColumns.MASTER_KEY_ID + ") ON DELETE CASCADE"
|
+ Tables.KEY_RINGS_PUBLIC + "(" + KeyRingsColumns.MASTER_KEY_ID + ") ON DELETE CASCADE"
|
||||||
+ ")";
|
+ ")";
|
||||||
@ -267,6 +266,13 @@ public class KeychainDatabase extends SQLiteOpenHelper {
|
|||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// never mind, the column probably already existed
|
// never mind, the column probably already existed
|
||||||
}
|
}
|
||||||
|
case 9:
|
||||||
|
// tbale name for user_ids changed to user_packets
|
||||||
|
db.execSQL("DROP TABLE IF EXISTS certs");
|
||||||
|
db.execSQL("DROP TABLE IF EXISTS user_ids");
|
||||||
|
db.execSQL(CREATE_USER_PACKETS);
|
||||||
|
db.execSQL(CREATE_CERTS);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// always do consolidate after upgrade
|
// always do consolidate after upgrade
|
||||||
|
@ -62,6 +62,7 @@ public class KeychainProvider extends ContentProvider {
|
|||||||
private static final int KEY_RING_SECRET = 204;
|
private static final int KEY_RING_SECRET = 204;
|
||||||
private static final int KEY_RING_CERTS = 205;
|
private static final int KEY_RING_CERTS = 205;
|
||||||
private static final int KEY_RING_CERTS_SPECIFIC = 206;
|
private static final int KEY_RING_CERTS_SPECIFIC = 206;
|
||||||
|
private static final int KEY_RING_LINKED_IDS = 207;
|
||||||
|
|
||||||
private static final int API_APPS = 301;
|
private static final int API_APPS = 301;
|
||||||
private static final int API_APPS_BY_PACKAGE_NAME = 302;
|
private static final int API_APPS_BY_PACKAGE_NAME = 302;
|
||||||
@ -127,6 +128,7 @@ public class KeychainProvider extends ContentProvider {
|
|||||||
* key_rings/_/unified
|
* key_rings/_/unified
|
||||||
* key_rings/_/keys
|
* key_rings/_/keys
|
||||||
* key_rings/_/user_ids
|
* key_rings/_/user_ids
|
||||||
|
* key_rings/_/linked_ids
|
||||||
* key_rings/_/public
|
* key_rings/_/public
|
||||||
* key_rings/_/secret
|
* key_rings/_/secret
|
||||||
* key_rings/_/certs
|
* key_rings/_/certs
|
||||||
@ -142,6 +144,9 @@ public class KeychainProvider extends ContentProvider {
|
|||||||
matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/*/"
|
matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/*/"
|
||||||
+ KeychainContract.PATH_USER_IDS,
|
+ KeychainContract.PATH_USER_IDS,
|
||||||
KEY_RING_USER_IDS);
|
KEY_RING_USER_IDS);
|
||||||
|
matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/*/"
|
||||||
|
+ KeychainContract.PATH_LINKED_IDS,
|
||||||
|
KEY_RING_LINKED_IDS);
|
||||||
matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/*/"
|
matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/*/"
|
||||||
+ KeychainContract.PATH_PUBLIC,
|
+ KeychainContract.PATH_PUBLIC,
|
||||||
KEY_RING_PUBLIC);
|
KEY_RING_PUBLIC);
|
||||||
@ -469,7 +474,8 @@ public class KeychainProvider extends ContentProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case KEY_RINGS_USER_IDS:
|
case KEY_RINGS_USER_IDS:
|
||||||
case KEY_RING_USER_IDS: {
|
case KEY_RING_USER_IDS:
|
||||||
|
case KEY_RING_LINKED_IDS: {
|
||||||
HashMap<String, String> projectionMap = new HashMap<>();
|
HashMap<String, String> projectionMap = new HashMap<>();
|
||||||
projectionMap.put(UserPackets._ID, Tables.USER_PACKETS + ".oid AS _id");
|
projectionMap.put(UserPackets._ID, Tables.USER_PACKETS + ".oid AS _id");
|
||||||
projectionMap.put(UserPackets.MASTER_KEY_ID, Tables.USER_PACKETS + "." + UserPackets.MASTER_KEY_ID);
|
projectionMap.put(UserPackets.MASTER_KEY_ID, Tables.USER_PACKETS + "." + UserPackets.MASTER_KEY_ID);
|
||||||
@ -494,13 +500,14 @@ public class KeychainProvider extends ContentProvider {
|
|||||||
groupBy = Tables.USER_PACKETS + "." + UserPackets.MASTER_KEY_ID
|
groupBy = Tables.USER_PACKETS + "." + UserPackets.MASTER_KEY_ID
|
||||||
+ ", " + Tables.USER_PACKETS + "." + UserPackets.RANK;
|
+ ", " + Tables.USER_PACKETS + "." + UserPackets.RANK;
|
||||||
|
|
||||||
// for now, we only respect user ids here, so TYPE must be NULL
|
if (match == KEY_RING_LINKED_IDS) {
|
||||||
// TODO expand with KEY_RING_USER_PACKETS query type which lifts this restriction
|
qb.appendWhere(Tables.USER_PACKETS + "." + UserPackets.TYPE + " = 100");
|
||||||
qb.appendWhere(Tables.USER_PACKETS + "." + UserPackets.TYPE + " IS NULL");
|
} else {
|
||||||
|
qb.appendWhere(Tables.USER_PACKETS + "." + UserPackets.TYPE + " IS NULL");
|
||||||
|
}
|
||||||
|
|
||||||
// If we are searching for a particular keyring's ids, add where
|
// If we are searching for a particular keyring's ids, add where
|
||||||
if (match == KEY_RING_USER_IDS) {
|
if (match == KEY_RING_USER_IDS || match == KEY_RING_LINKED_IDS) {
|
||||||
// TODO remove with the thing above
|
|
||||||
qb.appendWhere(" AND ");
|
qb.appendWhere(" AND ");
|
||||||
qb.appendWhere(Tables.USER_PACKETS + "." + UserPackets.MASTER_KEY_ID + " = ");
|
qb.appendWhere(Tables.USER_PACKETS + "." + UserPackets.MASTER_KEY_ID + " = ");
|
||||||
qb.appendWhereEscapeString(uri.getPathSegments().get(1));
|
qb.appendWhereEscapeString(uri.getPathSegments().get(1));
|
||||||
|
@ -1082,9 +1082,8 @@ public class ProviderHelper {
|
|||||||
log.add(LogType.MSG_CON_SAVE_SECRET, indent);
|
log.add(LogType.MSG_CON_SAVE_SECRET, indent);
|
||||||
indent += 1;
|
indent += 1;
|
||||||
|
|
||||||
final Cursor cursor = mContentResolver.query(KeyRings.buildUnifiedKeyRingsUri(), new String[]{
|
final Cursor cursor = mContentResolver.query(KeyRingData.buildSecretKeyRingUri(),
|
||||||
KeyRings.PRIVKEY_DATA, KeyRings.FINGERPRINT, KeyRings.HAS_ANY_SECRET
|
new String[]{ KeyRingData.KEY_RING_DATA }, null, null, null);
|
||||||
}, KeyRings.HAS_ANY_SECRET + " = 1", null, null);
|
|
||||||
|
|
||||||
if (cursor == null) {
|
if (cursor == null) {
|
||||||
log.add(LogType.MSG_CON_ERROR_DB, indent);
|
log.add(LogType.MSG_CON_ERROR_DB, indent);
|
||||||
@ -1106,8 +1105,7 @@ public class ProviderHelper {
|
|||||||
if (cursor.isAfterLast()) {
|
if (cursor.isAfterLast()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ring = new ParcelableKeyRing(KeyFormattingUtils.convertFingerprintToHex(cursor.getBlob(1)), cursor.getBlob(0)
|
ring = new ParcelableKeyRing(cursor.getBlob(0));
|
||||||
);
|
|
||||||
cursor.moveToNext();
|
cursor.moveToNext();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1144,9 +1142,9 @@ public class ProviderHelper {
|
|||||||
log.add(LogType.MSG_CON_SAVE_PUBLIC, indent);
|
log.add(LogType.MSG_CON_SAVE_PUBLIC, indent);
|
||||||
indent += 1;
|
indent += 1;
|
||||||
|
|
||||||
final Cursor cursor = mContentResolver.query(KeyRings.buildUnifiedKeyRingsUri(), new String[]{
|
final Cursor cursor = mContentResolver.query(
|
||||||
KeyRings.PUBKEY_DATA, KeyRings.FINGERPRINT
|
KeyRingData.buildPublicKeyRingUri(),
|
||||||
}, null, null, null);
|
new String[]{ KeyRingData.KEY_RING_DATA }, null, null, null);
|
||||||
|
|
||||||
if (cursor == null) {
|
if (cursor == null) {
|
||||||
log.add(LogType.MSG_CON_ERROR_DB, indent);
|
log.add(LogType.MSG_CON_ERROR_DB, indent);
|
||||||
@ -1168,8 +1166,7 @@ public class ProviderHelper {
|
|||||||
if (cursor.isAfterLast()) {
|
if (cursor.isAfterLast()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ring = new ParcelableKeyRing(KeyFormattingUtils.convertFingerprintToHex(cursor.getBlob(1)), cursor.getBlob(0)
|
ring = new ParcelableKeyRing(cursor.getBlob(0));
|
||||||
);
|
|
||||||
cursor.moveToNext();
|
cursor.moveToNext();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -281,7 +281,7 @@ public class ViewKeyActivity extends BaseActivity implements
|
|||||||
// Add the fragment to the 'fragment_container' FrameLayout
|
// Add the fragment to the 'fragment_container' FrameLayout
|
||||||
// NOTE: We use commitAllowingStateLoss() to prevent weird crashes!
|
// NOTE: We use commitAllowingStateLoss() to prevent weird crashes!
|
||||||
getSupportFragmentManager().beginTransaction()
|
getSupportFragmentManager().beginTransaction()
|
||||||
.replace(R.id.view_key_fragment, frag)
|
.replace(R.id.view_key_fragment, frag, "main")
|
||||||
.commitAllowingStateLoss();
|
.commitAllowingStateLoss();
|
||||||
// do it immediately!
|
// do it immediately!
|
||||||
getSupportFragmentManager().executePendingTransactions();
|
getSupportFragmentManager().executePendingTransactions();
|
||||||
|
@ -20,15 +20,22 @@ package org.sufficientlysecure.keychain.ui;
|
|||||||
|
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.support.v4.app.Fragment;
|
||||||
import android.support.v4.app.LoaderManager;
|
import android.support.v4.app.LoaderManager;
|
||||||
import android.support.v4.content.CursorLoader;
|
import android.support.v4.content.CursorLoader;
|
||||||
import android.support.v4.content.Loader;
|
import android.support.v4.content.Loader;
|
||||||
import android.support.v7.widget.CardView;
|
import android.support.v7.widget.CardView;
|
||||||
|
import android.transition.Explode;
|
||||||
|
import android.transition.Fade;
|
||||||
|
import android.transition.Transition;
|
||||||
|
import android.transition.TransitionInflater;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.AdapterView;
|
import android.widget.AdapterView;
|
||||||
|
import android.widget.AdapterView.OnItemClickListener;
|
||||||
import android.widget.ListView;
|
import android.widget.ListView;
|
||||||
|
|
||||||
import org.sufficientlysecure.keychain.Constants;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
@ -91,11 +98,34 @@ public class ViewKeyFragment extends LoaderFragment implements
|
|||||||
showUserIdInfo(position);
|
showUserIdInfo(position);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
mLinkedIdsCard.setVisibility(View.GONE);
|
mLinkedIds.setOnItemClickListener(new OnItemClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||||
|
showLinkedId(position);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void showLinkedId(final int position) {
|
||||||
|
Fragment frag = mLinkedIdsAdapter.getLinkedIdFragment(position);
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
|
Transition trans = TransitionInflater.from(getActivity())
|
||||||
|
.inflateTransition(R.transition.linked_id_card_trans);
|
||||||
|
// setSharedElementReturnTransition(trans);
|
||||||
|
setExitTransition(new Fade());
|
||||||
|
frag.setSharedElementEnterTransition(trans);
|
||||||
|
}
|
||||||
|
|
||||||
|
getFragmentManager().beginTransaction()
|
||||||
|
.replace(R.id.view_key_fragment, frag)
|
||||||
|
.addSharedElement(mLinkedIdsCard, "card_linked_ids")
|
||||||
|
.addToBackStack(null)
|
||||||
|
.commit();
|
||||||
|
}
|
||||||
|
|
||||||
private void showUserIdInfo(final int position) {
|
private void showUserIdInfo(final int position) {
|
||||||
if (!mIsSecret) {
|
if (!mIsSecret) {
|
||||||
final boolean isRevoked = mUserIdsAdapter.getIsRevoked(position);
|
final boolean isRevoked = mUserIdsAdapter.getIsRevoked(position);
|
||||||
@ -140,10 +170,8 @@ public class ViewKeyFragment extends LoaderFragment implements
|
|||||||
|
|
||||||
Log.i(Constants.TAG, "mDataUri: " + mDataUri);
|
Log.i(Constants.TAG, "mDataUri: " + mDataUri);
|
||||||
|
|
||||||
// Prepare the loaders. Either re-connect with an existing ones,
|
|
||||||
// or start new ones.
|
|
||||||
// TODO Is this loader the same as the one in the activity?
|
|
||||||
getLoaderManager().initLoader(LOADER_ID_UNIFIED, null, this);
|
getLoaderManager().initLoader(LOADER_ID_UNIFIED, null, this);
|
||||||
|
getLoaderManager().initLoader(LOADER_ID_LINKED_IDS, null, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
|
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
|
||||||
|
@ -21,24 +21,35 @@ package org.sufficientlysecure.keychain.ui.adapter;
|
|||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.graphics.Typeface;
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.support.v4.app.Fragment;
|
||||||
import android.support.v4.content.CursorLoader;
|
import android.support.v4.content.CursorLoader;
|
||||||
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.pgp.KeyRing;
|
import org.sufficientlysecure.keychain.pgp.linked.LinkedIdentity;
|
||||||
|
import org.sufficientlysecure.keychain.pgp.linked.LinkedResource;
|
||||||
import org.sufficientlysecure.keychain.pgp.linked.RawLinkedIdentity;
|
import org.sufficientlysecure.keychain.pgp.linked.RawLinkedIdentity;
|
||||||
|
import org.sufficientlysecure.keychain.pgp.linked.resources.DnsResource;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract.Certs;
|
import org.sufficientlysecure.keychain.provider.KeychainContract.Certs;
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets;
|
import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets;
|
||||||
|
import org.sufficientlysecure.keychain.ui.ViewKeyFragment;
|
||||||
|
import org.sufficientlysecure.keychain.ui.linked.LinkedIdViewFragment;
|
||||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.WeakHashMap;
|
||||||
|
|
||||||
|
|
||||||
public class LinkedIdsAdapter extends UserAttributesAdapter {
|
public class LinkedIdsAdapter extends UserAttributesAdapter {
|
||||||
protected LayoutInflater mInflater;
|
protected LayoutInflater mInflater;
|
||||||
|
WeakHashMap<Integer,RawLinkedIdentity> mLinkedIdentityCache = new WeakHashMap<>();
|
||||||
|
|
||||||
public LinkedIdsAdapter(Context context, Cursor c, int flags) {
|
public LinkedIdsAdapter(Context context, Cursor c, int flags) {
|
||||||
super(context, c, flags);
|
super(context, c, flags);
|
||||||
@ -46,104 +57,92 @@ public class LinkedIdsAdapter extends UserAttributesAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getItemViewType(int position) {
|
public void bindView(View view, Context context, Cursor cursor) {
|
||||||
RawLinkedIdentity id = (RawLinkedIdentity) getItem(position);
|
|
||||||
|
|
||||||
// TODO return different ids by type
|
RawLinkedIdentity id = getItem(cursor.getPosition());
|
||||||
|
ViewHolder holder = (ViewHolder) view.getTag();
|
||||||
|
|
||||||
|
int isVerified = cursor.getInt(INDEX_VERIFIED);
|
||||||
|
switch (isVerified) {
|
||||||
|
case Certs.VERIFIED_SECRET:
|
||||||
|
KeyFormattingUtils.setStatusImage(mContext, holder.vVerified,
|
||||||
|
null, KeyFormattingUtils.STATE_VERIFIED, KeyFormattingUtils.DEFAULT_COLOR);
|
||||||
|
break;
|
||||||
|
case Certs.VERIFIED_SELF:
|
||||||
|
KeyFormattingUtils.setStatusImage(mContext, holder.vVerified,
|
||||||
|
null, KeyFormattingUtils.STATE_UNVERIFIED, KeyFormattingUtils.DEFAULT_COLOR);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
KeyFormattingUtils.setStatusImage(mContext, holder.vVerified,
|
||||||
|
null, KeyFormattingUtils.STATE_INVALID, KeyFormattingUtils.DEFAULT_COLOR);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (holder instanceof ViewHolderNonRaw) {
|
||||||
|
((ViewHolderNonRaw) holder).setData(mContext, (LinkedIdentity) id);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemViewType(int position) {
|
||||||
|
RawLinkedIdentity id = getItem(position);
|
||||||
|
|
||||||
|
if (id instanceof LinkedIdentity) {
|
||||||
|
LinkedResource res = ((LinkedIdentity) id).mResource;
|
||||||
|
if (res instanceof DnsResource) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getViewTypeCount() {
|
public int getViewTypeCount() {
|
||||||
return 1;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getItem(int position) {
|
public RawLinkedIdentity getItem(int position) {
|
||||||
|
RawLinkedIdentity ret = mLinkedIdentityCache.get(position);
|
||||||
|
if (ret != null) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
Cursor c = getCursor();
|
Cursor c = getCursor();
|
||||||
c.moveToPosition(position);
|
c.moveToPosition(position);
|
||||||
|
|
||||||
byte[] data = c.getBlob(INDEX_ATTRIBUTE_DATA);
|
byte[] data = c.getBlob(INDEX_ATTRIBUTE_DATA);
|
||||||
RawLinkedIdentity identity = RawLinkedIdentity.fromSubpacketData(data);
|
try {
|
||||||
|
ret = LinkedIdentity.fromAttributeData(data);
|
||||||
return identity;
|
mLinkedIdentityCache.put(position, ret);
|
||||||
}
|
return ret;
|
||||||
|
} catch (IOException e) {
|
||||||
@Override
|
Log.e(Constants.TAG, "could not read linked identity subpacket data", e);
|
||||||
public void bindView(View view, Context context, Cursor cursor) {
|
return null;
|
||||||
TextView vName = (TextView) view.findViewById(R.id.user_id_item_name);
|
|
||||||
TextView vAddress = (TextView) view.findViewById(R.id.user_id_item_address);
|
|
||||||
TextView vComment = (TextView) view.findViewById(R.id.user_id_item_comment);
|
|
||||||
ImageView vVerified = (ImageView) view.findViewById(R.id.user_id_item_certified);
|
|
||||||
View vVerifiedLayout = view.findViewById(R.id.user_id_item_certified_layout);
|
|
||||||
ImageView vEditImage = (ImageView) view.findViewById(R.id.user_id_item_edit_image);
|
|
||||||
ImageView vDeleteButton = (ImageView) view.findViewById(R.id.user_id_item_delete_button);
|
|
||||||
vDeleteButton.setVisibility(View.GONE); // not used
|
|
||||||
|
|
||||||
String userId = cursor.getString(INDEX_USER_ID);
|
|
||||||
String[] splitUserId = KeyRing.splitUserId(userId);
|
|
||||||
if (splitUserId[0] != null) {
|
|
||||||
vName.setText(splitUserId[0]);
|
|
||||||
} else {
|
|
||||||
vName.setText(R.string.user_id_no_name);
|
|
||||||
}
|
|
||||||
if (splitUserId[1] != null) {
|
|
||||||
vAddress.setText(splitUserId[1]);
|
|
||||||
vAddress.setVisibility(View.VISIBLE);
|
|
||||||
} else {
|
|
||||||
vAddress.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
if (splitUserId[2] != null) {
|
|
||||||
vComment.setText(splitUserId[2]);
|
|
||||||
vComment.setVisibility(View.VISIBLE);
|
|
||||||
} else {
|
|
||||||
vComment.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean isPrimary = cursor.getInt(INDEX_IS_PRIMARY) != 0;
|
|
||||||
boolean isRevoked = cursor.getInt(INDEX_IS_REVOKED) > 0;
|
|
||||||
vVerifiedLayout.setVisibility(View.VISIBLE);
|
|
||||||
|
|
||||||
if (isRevoked) {
|
|
||||||
// set revocation icon (can this even be primary?)
|
|
||||||
KeyFormattingUtils.setStatusImage(mContext, vVerified, null, KeyFormattingUtils.STATE_REVOKED, R.color.bg_gray);
|
|
||||||
|
|
||||||
// disable revoked user ids
|
|
||||||
vName.setEnabled(false);
|
|
||||||
vAddress.setEnabled(false);
|
|
||||||
vComment.setEnabled(false);
|
|
||||||
} else {
|
|
||||||
vName.setEnabled(true);
|
|
||||||
vAddress.setEnabled(true);
|
|
||||||
vComment.setEnabled(true);
|
|
||||||
|
|
||||||
if (isPrimary) {
|
|
||||||
vName.setTypeface(null, Typeface.BOLD);
|
|
||||||
vAddress.setTypeface(null, Typeface.BOLD);
|
|
||||||
} else {
|
|
||||||
vName.setTypeface(null, Typeface.NORMAL);
|
|
||||||
vAddress.setTypeface(null, Typeface.NORMAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
int isVerified = cursor.getInt(INDEX_VERIFIED);
|
|
||||||
switch (isVerified) {
|
|
||||||
case Certs.VERIFIED_SECRET:
|
|
||||||
KeyFormattingUtils.setStatusImage(mContext, vVerified, null, KeyFormattingUtils.STATE_VERIFIED, KeyFormattingUtils.DEFAULT_COLOR);
|
|
||||||
break;
|
|
||||||
case Certs.VERIFIED_SELF:
|
|
||||||
KeyFormattingUtils.setStatusImage(mContext, vVerified, null, KeyFormattingUtils.STATE_UNVERIFIED, KeyFormattingUtils.DEFAULT_COLOR);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
KeyFormattingUtils.setStatusImage(mContext, vVerified, null, KeyFormattingUtils.STATE_INVALID, KeyFormattingUtils.DEFAULT_COLOR);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View newView(Context context, Cursor cursor, ViewGroup parent) {
|
public View newView(Context context, Cursor cursor, ViewGroup parent) {
|
||||||
return mInflater.inflate(R.layout.view_key_adv_user_id_item, null);
|
int type = getItemViewType(cursor.getPosition());
|
||||||
|
switch(type) {
|
||||||
|
case 0: {
|
||||||
|
View v = mInflater.inflate(R.layout.linked_id_item_unknown, null);
|
||||||
|
ViewHolder holder = new ViewHolder(v);
|
||||||
|
v.setTag(holder);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
case 1: {
|
||||||
|
View v = mInflater.inflate(R.layout.linked_id_item_dns, null);
|
||||||
|
ViewHolder holder = new ViewHolderDns(v);
|
||||||
|
v.setTag(holder);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw new AssertionError("all cases must be covered in LinkedIdsAdapter.newView!");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// don't show revoked user ids, irrelevant for average users
|
// don't show revoked user ids, irrelevant for average users
|
||||||
@ -155,4 +154,48 @@ public class LinkedIdsAdapter extends UserAttributesAdapter {
|
|||||||
UserIdsAdapter.USER_PACKETS_PROJECTION, LINKED_IDS_WHERE, null, null);
|
UserIdsAdapter.USER_PACKETS_PROJECTION, LINKED_IDS_WHERE, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Fragment getLinkedIdFragment(int position) {
|
||||||
|
RawLinkedIdentity id = getItem(position);
|
||||||
|
|
||||||
|
return LinkedIdViewFragment.newInstance(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
static class ViewHolder {
|
||||||
|
ImageView vVerified;
|
||||||
|
|
||||||
|
ViewHolder(View view) {
|
||||||
|
vVerified = (ImageView) view.findViewById(R.id.user_id_item_certified);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static abstract class ViewHolderNonRaw extends ViewHolder {
|
||||||
|
ViewHolderNonRaw(View view) {
|
||||||
|
super(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract void setData(Context context, LinkedIdentity id);
|
||||||
|
}
|
||||||
|
|
||||||
|
static class ViewHolderDns extends ViewHolderNonRaw {
|
||||||
|
TextView vFqdn;
|
||||||
|
|
||||||
|
ViewHolderDns(View view) {
|
||||||
|
super(view);
|
||||||
|
|
||||||
|
vFqdn = (TextView) view.findViewById(R.id.linked_id_dns_fqdn);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void setData(Context context, LinkedIdentity id) {
|
||||||
|
DnsResource res = (DnsResource) id.mResource;
|
||||||
|
vFqdn.setText(res.getFqdn());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void notifyDataSetChanged() {
|
||||||
|
mLinkedIdentityCache.clear();
|
||||||
|
super.notifyDataSetChanged();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,4 +48,5 @@ public abstract class UserAttributesAdapter extends CursorAdapter {
|
|||||||
mCursor.moveToPosition(position);
|
mCursor.moveToPosition(position);
|
||||||
return mCursor.getInt(INDEX_VERIFIED);
|
return mCursor.getInt(INDEX_VERIFIED);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -73,7 +73,7 @@ public class LinkedIdCreateDnsStep1Fragment extends Fragment {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String proofNonce = RawLinkedIdentity.generateNonce();
|
int proofNonce = RawLinkedIdentity.generateNonce();
|
||||||
String proofText = DnsResource.generateText(getActivity(),
|
String proofText = DnsResource.generateText(getActivity(),
|
||||||
mLinkedIdWizard.mFingerprint, proofNonce);
|
mLinkedIdWizard.mFingerprint, proofNonce);
|
||||||
|
|
||||||
|
@ -41,6 +41,7 @@ import org.sufficientlysecure.keychain.R;
|
|||||||
import org.sufficientlysecure.keychain.operations.results.LinkedVerifyResult;
|
import org.sufficientlysecure.keychain.operations.results.LinkedVerifyResult;
|
||||||
import org.sufficientlysecure.keychain.operations.results.OperationResult;
|
import org.sufficientlysecure.keychain.operations.results.OperationResult;
|
||||||
import org.sufficientlysecure.keychain.pgp.WrappedUserAttribute;
|
import org.sufficientlysecure.keychain.pgp.WrappedUserAttribute;
|
||||||
|
import org.sufficientlysecure.keychain.pgp.linked.LinkedIdentity;
|
||||||
import org.sufficientlysecure.keychain.pgp.linked.RawLinkedIdentity;
|
import org.sufficientlysecure.keychain.pgp.linked.RawLinkedIdentity;
|
||||||
import org.sufficientlysecure.keychain.pgp.linked.resources.DnsResource;
|
import org.sufficientlysecure.keychain.pgp.linked.resources.DnsResource;
|
||||||
import org.sufficientlysecure.keychain.service.KeychainIntentService;
|
import org.sufficientlysecure.keychain.service.KeychainIntentService;
|
||||||
@ -80,13 +81,13 @@ public class LinkedIdCreateDnsStep2Fragment extends Fragment {
|
|||||||
* Creates new instance of this fragment
|
* Creates new instance of this fragment
|
||||||
*/
|
*/
|
||||||
public static LinkedIdCreateDnsStep2Fragment newInstance
|
public static LinkedIdCreateDnsStep2Fragment newInstance
|
||||||
(String uri, String proofNonce, String proofText) {
|
(String uri, int proofNonce, String proofText) {
|
||||||
|
|
||||||
LinkedIdCreateDnsStep2Fragment frag = new LinkedIdCreateDnsStep2Fragment();
|
LinkedIdCreateDnsStep2Fragment frag = new LinkedIdCreateDnsStep2Fragment();
|
||||||
|
|
||||||
Bundle args = new Bundle();
|
Bundle args = new Bundle();
|
||||||
args.putString(DOMAIN, uri);
|
args.putString(DOMAIN, uri);
|
||||||
args.putString(NONCE, proofNonce);
|
args.putInt(NONCE, proofNonce);
|
||||||
args.putString(TEXT, proofText);
|
args.putString(TEXT, proofText);
|
||||||
frag.setArguments(args);
|
frag.setArguments(args);
|
||||||
|
|
||||||
@ -237,6 +238,7 @@ public class LinkedIdCreateDnsStep2Fragment extends Fragment {
|
|||||||
mVerifiedResource = resource;
|
mVerifiedResource = resource;
|
||||||
} else {
|
} else {
|
||||||
setVerifyProgress(false, false);
|
setVerifyProgress(false, false);
|
||||||
|
mVerifiedResource = resource;
|
||||||
// on error, show error message
|
// on error, show error message
|
||||||
result.createNotify(getActivity()).show();
|
result.createNotify(getActivity()).show();
|
||||||
}
|
}
|
||||||
@ -308,7 +310,7 @@ public class LinkedIdCreateDnsStep2Fragment extends Fragment {
|
|||||||
new SaveKeyringParcel(mLinkedIdWizard.mMasterKeyId, mLinkedIdWizard.mFingerprint);
|
new SaveKeyringParcel(mLinkedIdWizard.mMasterKeyId, mLinkedIdWizard.mFingerprint);
|
||||||
|
|
||||||
WrappedUserAttribute ua =
|
WrappedUserAttribute ua =
|
||||||
RawLinkedIdentity.fromResource(mVerifiedResource, mResourceNonce).toUserAttribute();
|
LinkedIdentity.fromResource(mVerifiedResource, mResourceNonce).toUserAttribute();
|
||||||
|
|
||||||
skp.mAddUserAttribute.add(ua);
|
skp.mAddUserAttribute.add(ua);
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ public class LinkedIdCreateHttpsStep1Fragment extends Fragment {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String proofNonce = RawLinkedIdentity.generateNonce();
|
int proofNonce = RawLinkedIdentity.generateNonce();
|
||||||
String proofText = GenericHttpsResource.generateText(getActivity(),
|
String proofText = GenericHttpsResource.generateText(getActivity(),
|
||||||
mLinkedIdWizard.mFingerprint, proofNonce);
|
mLinkedIdWizard.mFingerprint, proofNonce);
|
||||||
|
|
||||||
|
@ -42,6 +42,7 @@ import org.sufficientlysecure.keychain.R;
|
|||||||
import org.sufficientlysecure.keychain.operations.results.LinkedVerifyResult;
|
import org.sufficientlysecure.keychain.operations.results.LinkedVerifyResult;
|
||||||
import org.sufficientlysecure.keychain.operations.results.OperationResult;
|
import org.sufficientlysecure.keychain.operations.results.OperationResult;
|
||||||
import org.sufficientlysecure.keychain.pgp.WrappedUserAttribute;
|
import org.sufficientlysecure.keychain.pgp.WrappedUserAttribute;
|
||||||
|
import org.sufficientlysecure.keychain.pgp.linked.LinkedIdentity;
|
||||||
import org.sufficientlysecure.keychain.pgp.linked.RawLinkedIdentity;
|
import org.sufficientlysecure.keychain.pgp.linked.RawLinkedIdentity;
|
||||||
import org.sufficientlysecure.keychain.pgp.linked.resources.GenericHttpsResource;
|
import org.sufficientlysecure.keychain.pgp.linked.resources.GenericHttpsResource;
|
||||||
import org.sufficientlysecure.keychain.service.KeychainIntentService;
|
import org.sufficientlysecure.keychain.service.KeychainIntentService;
|
||||||
@ -83,13 +84,13 @@ public class LinkedIdCreateHttpsStep2Fragment extends Fragment {
|
|||||||
* Creates new instance of this fragment
|
* Creates new instance of this fragment
|
||||||
*/
|
*/
|
||||||
public static LinkedIdCreateHttpsStep2Fragment newInstance
|
public static LinkedIdCreateHttpsStep2Fragment newInstance
|
||||||
(String uri, String proofNonce, String proofText) {
|
(String uri, int proofNonce, String proofText) {
|
||||||
|
|
||||||
LinkedIdCreateHttpsStep2Fragment frag = new LinkedIdCreateHttpsStep2Fragment();
|
LinkedIdCreateHttpsStep2Fragment frag = new LinkedIdCreateHttpsStep2Fragment();
|
||||||
|
|
||||||
Bundle args = new Bundle();
|
Bundle args = new Bundle();
|
||||||
args.putString(URI, uri);
|
args.putString(URI, uri);
|
||||||
args.putString(NONCE, proofNonce);
|
args.putInt(NONCE, proofNonce);
|
||||||
args.putString(TEXT, proofText);
|
args.putString(TEXT, proofText);
|
||||||
frag.setArguments(args);
|
frag.setArguments(args);
|
||||||
|
|
||||||
@ -315,7 +316,7 @@ public class LinkedIdCreateHttpsStep2Fragment extends Fragment {
|
|||||||
new SaveKeyringParcel(mLinkedIdWizard.mMasterKeyId, mLinkedIdWizard.mFingerprint);
|
new SaveKeyringParcel(mLinkedIdWizard.mMasterKeyId, mLinkedIdWizard.mFingerprint);
|
||||||
|
|
||||||
WrappedUserAttribute ua =
|
WrappedUserAttribute ua =
|
||||||
RawLinkedIdentity.fromResource(mVerifiedResource, mResourceNonce).toUserAttribute();
|
LinkedIdentity.fromResource(mVerifiedResource, mResourceNonce).toUserAttribute();
|
||||||
|
|
||||||
skp.mAddUserAttribute.add(ua);
|
skp.mAddUserAttribute.add(ua);
|
||||||
|
|
||||||
|
@ -92,7 +92,7 @@ public class LinkedIdCreateTwitterStep1Fragment extends Fragment {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String proofNonce = RawLinkedIdentity.generateNonce();
|
int proofNonce = RawLinkedIdentity.generateNonce();
|
||||||
String proofText = TwitterResource.generateText(getActivity(),
|
String proofText = TwitterResource.generateText(getActivity(),
|
||||||
mLinkedIdWizard.mFingerprint, proofNonce);
|
mLinkedIdWizard.mFingerprint, proofNonce);
|
||||||
|
|
||||||
|
@ -52,13 +52,13 @@ public class LinkedIdCreateTwitterStep2Fragment extends Fragment {
|
|||||||
* Creates new instance of this fragment
|
* Creates new instance of this fragment
|
||||||
*/
|
*/
|
||||||
public static LinkedIdCreateTwitterStep2Fragment newInstance
|
public static LinkedIdCreateTwitterStep2Fragment newInstance
|
||||||
(String handle, String proofNonce, String proofText) {
|
(String handle, int proofNonce, String proofText) {
|
||||||
|
|
||||||
LinkedIdCreateTwitterStep2Fragment frag = new LinkedIdCreateTwitterStep2Fragment();
|
LinkedIdCreateTwitterStep2Fragment frag = new LinkedIdCreateTwitterStep2Fragment();
|
||||||
|
|
||||||
Bundle args = new Bundle();
|
Bundle args = new Bundle();
|
||||||
args.putString(HANDLE, handle);
|
args.putString(HANDLE, handle);
|
||||||
args.putString(NONCE, proofNonce);
|
args.putInt(NONCE, proofNonce);
|
||||||
args.putString(TEXT, proofText);
|
args.putString(TEXT, proofText);
|
||||||
frag.setArguments(args);
|
frag.setArguments(args);
|
||||||
|
|
||||||
|
@ -0,0 +1,45 @@
|
|||||||
|
package org.sufficientlysecure.keychain.ui.linked;
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.v4.app.Fragment;
|
||||||
|
import android.support.v7.widget.CardView;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.View.OnClickListener;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
|
import org.sufficientlysecure.keychain.R;
|
||||||
|
import org.sufficientlysecure.keychain.pgp.linked.RawLinkedIdentity;
|
||||||
|
|
||||||
|
|
||||||
|
public class LinkedIdViewFragment extends Fragment {
|
||||||
|
|
||||||
|
private CardView mLinkedIdsCard;
|
||||||
|
|
||||||
|
public static Fragment newInstance(RawLinkedIdentity id) {
|
||||||
|
LinkedIdViewFragment frag = new LinkedIdViewFragment();
|
||||||
|
|
||||||
|
Bundle args = new Bundle();
|
||||||
|
frag.setArguments(args);
|
||||||
|
|
||||||
|
return frag;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View onCreateView(LayoutInflater inflater, ViewGroup superContainer, Bundle savedInstanceState) {
|
||||||
|
View root = inflater.inflate(R.layout.linked_id_view_fragment, null);
|
||||||
|
|
||||||
|
mLinkedIdsCard = (CardView) root.findViewById(R.id.card_linked_ids);
|
||||||
|
|
||||||
|
root.findViewById(R.id.back_button).setClickable(true);
|
||||||
|
root.findViewById(R.id.back_button).setOnClickListener(new OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
getFragmentManager().popBackStack();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
63
OpenKeychain/src/main/res/layout/linked_id_item_dns.xml
Normal file
63
OpenKeychain/src/main/res/layout/linked_id_item_dns.xml
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:minHeight="?android:attr/listPreferredItemHeight"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:singleLine="true">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:id="@+id/linked_id_type_icon"
|
||||||
|
android:layout_marginLeft="14dp"
|
||||||
|
android:layout_marginStart="14dp"
|
||||||
|
android:src="@drawable/dns"
|
||||||
|
android:layout_gravity="center_vertical" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:layout_width="0dip"
|
||||||
|
android:layout_marginLeft="8dp"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
android:layout_marginBottom="4dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/linked_id_dns_fqdn"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="www.example.com"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceMedium" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/user_id_item_comment"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="@color/tertiary_text_light"
|
||||||
|
android:text="comment"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceSmall" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/user_id_item_certified_layout"
|
||||||
|
android:layout_width="22dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginRight="8dp"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/user_id_item_certified"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:src="@drawable/status_signature_unverified_cutout_24px"
|
||||||
|
android:layout_gravity="center_horizontal" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
54
OpenKeychain/src/main/res/layout/linked_id_item_unknown.xml
Normal file
54
OpenKeychain/src/main/res/layout/linked_id_item_unknown.xml
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:minHeight="?android:attr/listPreferredItemHeight"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:singleLine="true">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:layout_width="0dip"
|
||||||
|
android:layout_marginLeft="8dp"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
android:layout_marginBottom="4dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/linked_id_uri"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="uri"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceMedium" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/user_id_item_comment"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="@color/tertiary_text_light"
|
||||||
|
android:text="unknown linked identity type"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceSmall" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/user_id_item_certified_layout"
|
||||||
|
android:layout_width="22dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginRight="8dp"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/user_id_item_certified"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:src="@drawable/status_signature_unverified_cutout_24px"
|
||||||
|
android:layout_gravity="center_horizontal" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
94
OpenKeychain/src/main/res/layout/linked_id_view_fragment.xml
Normal file
94
OpenKeychain/src/main/res/layout/linked_id_view_fragment.xml
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:card_view="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:paddingTop="16dp"
|
||||||
|
android:paddingBottom="16dp"
|
||||||
|
android:paddingLeft="16dp"
|
||||||
|
android:paddingRight="16dp">
|
||||||
|
|
||||||
|
<android.support.v7.widget.CardView
|
||||||
|
android:id="@+id/card_linked_ids"
|
||||||
|
android:transitionName="card_linked_ids"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
card_view:cardBackgroundColor="@android:color/white"
|
||||||
|
card_view:cardElevation="2dp"
|
||||||
|
card_view:cardUseCompatPadding="true"
|
||||||
|
card_view:cardCornerRadius="4dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
style="@style/CardViewHeader"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Linked Identity" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:minHeight="?android:attr/listPreferredItemHeight"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:id="@+id/linked_id_type_icon"
|
||||||
|
android:layout_marginLeft="14dp"
|
||||||
|
android:layout_marginStart="14dp"
|
||||||
|
android:src="@drawable/dns" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="14dp"
|
||||||
|
android:layout_marginStart="14dp"
|
||||||
|
android:text="This is a DNS linked identity~\nLorem ipsum\nmore text\neven more text\nyoooyoyo"
|
||||||
|
android:layout_gravity="center_vertical" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/back_button"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:src="@drawable/ic_arrow_back_white_24dp"
|
||||||
|
style="?android:attr/borderlessButtonStyle" />
|
||||||
|
|
||||||
|
<Space
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="1" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="View"
|
||||||
|
android:textColor="@color/link_text_material_light"
|
||||||
|
style="?android:attr/borderlessButtonStyle"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Verify"
|
||||||
|
android:textColor="@color/link_text_material_light"
|
||||||
|
style="?android:attr/borderlessButtonStyle"
|
||||||
|
/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</android.support.v7.widget.CardView>
|
||||||
|
|
||||||
|
</ScrollView>
|
@ -43,6 +43,7 @@
|
|||||||
|
|
||||||
<android.support.v7.widget.CardView
|
<android.support.v7.widget.CardView
|
||||||
android:id="@+id/card_linked_ids"
|
android:id="@+id/card_linked_ids"
|
||||||
|
android:transitionName="card_linked_ids"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<changeBounds />
|
||||||
|
</transitionSet>
|
Loading…
x
Reference in New Issue
Block a user