mirror of
https://github.com/moparisthebest/open-keychain
synced 2024-11-11 03:25:05 -05:00
key lists somewhat wrapped into one, using the new database stuff, Apg cleaned up a bit, preparing to use the database there as well
This commit is contained in:
parent
e83f1e7b3a
commit
6f28f5ee4e
@ -36,8 +36,6 @@ import java.security.SecureRandom;
|
|||||||
import java.security.Security;
|
import java.security.Security;
|
||||||
import java.security.SignatureException;
|
import java.security.SignatureException;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.GregorianCalendar;
|
import java.util.GregorianCalendar;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@ -126,9 +124,6 @@ public class Apg {
|
|||||||
CompressionAlgorithmTags.BZIP2,
|
CompressionAlgorithmTags.BZIP2,
|
||||||
CompressionAlgorithmTags.ZIP };
|
CompressionAlgorithmTags.ZIP };
|
||||||
|
|
||||||
protected static Vector<PGPPublicKeyRing> mPublicKeyRings = new Vector<PGPPublicKeyRing>();
|
|
||||||
protected static Vector<PGPSecretKeyRing> mSecretKeyRings = new Vector<PGPSecretKeyRing>();
|
|
||||||
|
|
||||||
public static Pattern PGP_MESSAGE =
|
public static Pattern PGP_MESSAGE =
|
||||||
Pattern.compile(".*?(-----BEGIN PGP MESSAGE-----.*?-----END PGP MESSAGE-----).*",
|
Pattern.compile(".*?(-----BEGIN PGP MESSAGE-----.*?-----END PGP MESSAGE-----).*",
|
||||||
Pattern.DOTALL);
|
Pattern.DOTALL);
|
||||||
@ -137,13 +132,6 @@ public class Apg {
|
|||||||
Pattern.compile(".*?(-----BEGIN PGP SIGNED MESSAGE-----.*?-----BEGIN PGP SIGNATURE-----.*?-----END PGP SIGNATURE-----).*",
|
Pattern.compile(".*?(-----BEGIN PGP SIGNED MESSAGE-----.*?-----BEGIN PGP SIGNATURE-----.*?-----END PGP SIGNATURE-----).*",
|
||||||
Pattern.DOTALL);
|
Pattern.DOTALL);
|
||||||
|
|
||||||
protected static boolean mInitialized = false;
|
|
||||||
|
|
||||||
protected static HashMap<Long, Integer> mSecretKeyIdToIdMap;
|
|
||||||
protected static HashMap<Long, PGPSecretKeyRing> mSecretKeyIdToKeyRingMap;
|
|
||||||
protected static HashMap<Long, Integer> mPublicKeyIdToIdMap;
|
|
||||||
protected static HashMap<Long, PGPPublicKeyRing> mPublicKeyIdToKeyRingMap;
|
|
||||||
|
|
||||||
public static final String PUBLIC_KEY_PROJECTION[] =
|
public static final String PUBLIC_KEY_PROJECTION[] =
|
||||||
new String[] {
|
new String[] {
|
||||||
PublicKeys._ID,
|
PublicKeys._ID,
|
||||||
@ -177,104 +165,6 @@ public class Apg {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static {
|
|
||||||
mPublicKeyRings = new Vector<PGPPublicKeyRing>();
|
|
||||||
mSecretKeyRings = new Vector<PGPSecretKeyRing>();
|
|
||||||
mSecretKeyIdToIdMap = new HashMap<Long, Integer>();
|
|
||||||
mSecretKeyIdToKeyRingMap = new HashMap<Long, PGPSecretKeyRing>();
|
|
||||||
mPublicKeyIdToIdMap = new HashMap<Long, Integer>();
|
|
||||||
mPublicKeyIdToKeyRingMap = new HashMap<Long, PGPPublicKeyRing>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void initialize(Activity context) {
|
|
||||||
if (mInitialized) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
|
|
||||||
File dir = new File(Constants.path.app_dir);
|
|
||||||
if (!dir.exists() && !dir.mkdirs()) {
|
|
||||||
// ignore this for now, it's not crucial
|
|
||||||
// that the directory doesn't exist at this point
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
loadKeyRings(context, Id.type.public_key);
|
|
||||||
loadKeyRings(context, Id.type.secret_key);
|
|
||||||
|
|
||||||
mInitialized = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class PublicKeySorter implements Comparator<PGPPublicKeyRing> {
|
|
||||||
@Override
|
|
||||||
public int compare(PGPPublicKeyRing object1, PGPPublicKeyRing object2) {
|
|
||||||
PGPPublicKey key1 = getMasterKey(object1);
|
|
||||||
PGPPublicKey key2 = getMasterKey(object2);
|
|
||||||
if (key1 == null && key2 == null) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (key1 == null) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (key2 == null) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
String uid1 = getMainUserId(key1);
|
|
||||||
String uid2 = getMainUserId(key2);
|
|
||||||
if (uid1 == null && uid2 == null) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (uid1 == null) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (uid2 == null) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return uid1.compareTo(uid2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class SecretKeySorter implements Comparator<PGPSecretKeyRing> {
|
|
||||||
@Override
|
|
||||||
public int compare(PGPSecretKeyRing object1, PGPSecretKeyRing object2) {
|
|
||||||
PGPSecretKey key1 = getMasterKey(object1);
|
|
||||||
PGPSecretKey key2 = getMasterKey(object2);
|
|
||||||
if (key1 == null && key2 == null) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (key1 == null) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (key2 == null) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
String uid1 = getMainUserId(key1);
|
|
||||||
String uid2 = getMainUserId(key2);
|
|
||||||
if (uid1 == null && uid2 == null) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (uid1 == null) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (uid2 == null) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return uid1.compareTo(uid2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setEditPassPhrase(String passPhrase) {
|
public static void setEditPassPhrase(String passPhrase) {
|
||||||
mEditPassPhrase = passPhrase;
|
mEditPassPhrase = passPhrase;
|
||||||
}
|
}
|
||||||
@ -290,7 +180,7 @@ public class Apg {
|
|||||||
public static String getCachedPassPhrase(long keyId) {
|
public static String getCachedPassPhrase(long keyId) {
|
||||||
long realId = keyId;
|
long realId = keyId;
|
||||||
if (realId != Id.key.symmetric) {
|
if (realId != Id.key.symmetric) {
|
||||||
PGPSecretKeyRing keyRing = findSecretKeyRing(keyId);
|
PGPSecretKeyRing keyRing = getSecretKeyRing(keyId);
|
||||||
if (keyRing == null) {
|
if (keyRing == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -623,8 +513,6 @@ public class Apg {
|
|||||||
saveKeyRing(context, secretKeyRing);
|
saveKeyRing(context, secretKeyRing);
|
||||||
saveKeyRing(context, publicKeyRing);
|
saveKeyRing(context, publicKeyRing);
|
||||||
|
|
||||||
loadKeyRings(context, Id.type.public_key);
|
|
||||||
loadKeyRings(context, Id.type.secret_key);
|
|
||||||
progress.setProgress(R.string.progress_done, 100, 100);
|
progress.setProgress(R.string.progress_done, 100, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -754,7 +642,6 @@ public class Apg {
|
|||||||
}
|
}
|
||||||
|
|
||||||
progress.setProgress(R.string.progress_reloadingKeys, 100, 100);
|
progress.setProgress(R.string.progress_reloadingKeys, 100, 100);
|
||||||
loadKeyRings(context, type);
|
|
||||||
|
|
||||||
returnData.putInt("added", newKeys);
|
returnData.putInt("added", newKeys);
|
||||||
returnData.putInt("updated", oldKeys);
|
returnData.putInt("updated", oldKeys);
|
||||||
@ -808,61 +695,6 @@ public class Apg {
|
|||||||
return returnData;
|
return returnData;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void loadKeyRings(Activity context, int type) {
|
|
||||||
Cursor cursor;
|
|
||||||
if (type == Id.type.secret_key) {
|
|
||||||
mSecretKeyRings.clear();
|
|
||||||
mSecretKeyIdToIdMap.clear();
|
|
||||||
mSecretKeyIdToKeyRingMap.clear();
|
|
||||||
cursor = context.managedQuery(SecretKeys.CONTENT_URI, SECRET_KEY_PROJECTION,
|
|
||||||
null, null, null);
|
|
||||||
} else {
|
|
||||||
mPublicKeyRings.clear();
|
|
||||||
mPublicKeyIdToIdMap.clear();
|
|
||||||
mPublicKeyIdToKeyRingMap.clear();
|
|
||||||
cursor = context.managedQuery(PublicKeys.CONTENT_URI, PUBLIC_KEY_PROJECTION,
|
|
||||||
null, null, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < cursor.getCount(); ++i) {
|
|
||||||
cursor.moveToPosition(i);
|
|
||||||
String sharedIdColumn = PublicKeys._ID; // same in both
|
|
||||||
String sharedKeyIdColumn = PublicKeys.KEY_ID; // same in both
|
|
||||||
String sharedKeyDataColumn = PublicKeys.KEY_DATA; // same in both
|
|
||||||
int idIndex = cursor.getColumnIndex(sharedIdColumn);
|
|
||||||
int keyIdIndex = cursor.getColumnIndex(sharedKeyIdColumn);
|
|
||||||
int keyDataIndex = cursor.getColumnIndex(sharedKeyDataColumn);
|
|
||||||
|
|
||||||
byte keyData[] = cursor.getBlob(keyDataIndex);
|
|
||||||
int id = cursor.getInt(idIndex);
|
|
||||||
long keyId = cursor.getLong(keyIdIndex);
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (type == Id.type.secret_key) {
|
|
||||||
PGPSecretKeyRing key = new PGPSecretKeyRing(keyData);
|
|
||||||
mSecretKeyRings.add(key);
|
|
||||||
mSecretKeyIdToIdMap.put(keyId, id);
|
|
||||||
mSecretKeyIdToKeyRingMap.put(keyId, key);
|
|
||||||
} else {
|
|
||||||
PGPPublicKeyRing key = new PGPPublicKeyRing(keyData);
|
|
||||||
mPublicKeyRings.add(key);
|
|
||||||
mPublicKeyIdToIdMap.put(keyId, id);
|
|
||||||
mPublicKeyIdToKeyRingMap.put(keyId, key);
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
// TODO: some error handling
|
|
||||||
} catch (PGPException e) {
|
|
||||||
// TODO: some error handling
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type == Id.type.secret_key) {
|
|
||||||
Collections.sort(mSecretKeyRings, new SecretKeySorter());
|
|
||||||
} else {
|
|
||||||
Collections.sort(mPublicKeyRings, new PublicKeySorter());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Date getCreationDate(PGPPublicKey key) {
|
public static Date getCreationDate(PGPPublicKey key) {
|
||||||
return key.getCreationTime();
|
return key.getCreationTime();
|
||||||
}
|
}
|
||||||
@ -987,7 +819,7 @@ public class Apg {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static PGPPublicKey getEncryptPublicKey(long masterKeyId) {
|
public static PGPPublicKey getEncryptPublicKey(long masterKeyId) {
|
||||||
PGPPublicKeyRing keyRing = mPublicKeyIdToKeyRingMap.get(masterKeyId);
|
PGPPublicKeyRing keyRing = getPublicKeyRing(masterKeyId);
|
||||||
if (keyRing == null) {
|
if (keyRing == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -999,7 +831,7 @@ public class Apg {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static PGPSecretKey getSigningKey(long masterKeyId) {
|
public static PGPSecretKey getSigningKey(long masterKeyId) {
|
||||||
PGPSecretKeyRing keyRing = mSecretKeyIdToKeyRingMap.get(masterKeyId);
|
PGPSecretKeyRing keyRing = getSecretKeyRing(masterKeyId);
|
||||||
if (keyRing == null) {
|
if (keyRing == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -1040,14 +872,6 @@ public class Apg {
|
|||||||
return userId;
|
return userId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PGPPublicKeyRing getPublicKeyRing(long keyId) {
|
|
||||||
return mPublicKeyIdToKeyRingMap.get(keyId);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static PGPSecretKeyRing getSecretKeyRing(long keyId) {
|
|
||||||
return mSecretKeyIdToKeyRingMap.get(keyId);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isEncryptionKey(PGPPublicKey key) {
|
public static boolean isEncryptionKey(PGPPublicKey key) {
|
||||||
if (!key.isEncryptionKey()) {
|
if (!key.isEncryptionKey()) {
|
||||||
return false;
|
return false;
|
||||||
@ -1127,9 +951,17 @@ public class Apg {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static String getAlgorithmInfo(PGPPublicKey key) {
|
public static String getAlgorithmInfo(PGPPublicKey key) {
|
||||||
|
return getAlgorithmInfo(key.getAlgorithm(), key.getBitStrength());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getAlgorithmInfo(PGPSecretKey key) {
|
||||||
|
return getAlgorithmInfo(key.getPublicKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getAlgorithmInfo(int algorithm, int keySize) {
|
||||||
String algorithmStr = null;
|
String algorithmStr = null;
|
||||||
|
|
||||||
switch (key.getAlgorithm()) {
|
switch (algorithm) {
|
||||||
case PGPPublicKey.RSA_ENCRYPT:
|
case PGPPublicKey.RSA_ENCRYPT:
|
||||||
case PGPPublicKey.RSA_GENERAL:
|
case PGPPublicKey.RSA_GENERAL:
|
||||||
case PGPPublicKey.RSA_SIGN: {
|
case PGPPublicKey.RSA_SIGN: {
|
||||||
@ -1153,96 +985,38 @@ public class Apg {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return algorithmStr + ", " + key.getBitStrength() + "bit";
|
return algorithmStr + ", " + keySize + "bit";
|
||||||
}
|
|
||||||
|
|
||||||
public static String getAlgorithmInfo(PGPSecretKey key) {
|
|
||||||
return getAlgorithmInfo(key.getPublicKey());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void deleteKey(Activity context, PGPPublicKeyRing keyRing) {
|
public static void deleteKey(Activity context, PGPPublicKeyRing keyRing) {
|
||||||
PGPPublicKey masterKey = getMasterKey(keyRing);
|
PGPPublicKey masterKey = getMasterKey(keyRing);
|
||||||
Uri uri = Uri.withAppendedPath(PublicKeys.CONTENT_URI_BY_KEY_ID, "" + masterKey.getKeyID());
|
Uri uri = Uri.withAppendedPath(PublicKeys.CONTENT_URI_BY_KEY_ID, "" + masterKey.getKeyID());
|
||||||
context.getContentResolver().delete(uri, null, null);
|
context.getContentResolver().delete(uri, null, null);
|
||||||
loadKeyRings(context, Id.type.public_key);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void deleteKey(Activity context, PGPSecretKeyRing keyRing) {
|
public static void deleteKey(Activity context, PGPSecretKeyRing keyRing) {
|
||||||
PGPSecretKey masterKey = getMasterKey(keyRing);
|
PGPSecretKey masterKey = getMasterKey(keyRing);
|
||||||
Uri uri = Uri.withAppendedPath(SecretKeys.CONTENT_URI_BY_KEY_ID, "" + masterKey.getKeyID());
|
Uri uri = Uri.withAppendedPath(SecretKeys.CONTENT_URI_BY_KEY_ID, "" + masterKey.getKeyID());
|
||||||
context.getContentResolver().delete(uri, null, null);
|
context.getContentResolver().delete(uri, null, null);
|
||||||
loadKeyRings(context, Id.type.secret_key);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PGPPublicKey findPublicKey(long keyId) {
|
public static PGPSecretKeyRing getSecretKeyRing(long keyId) {
|
||||||
PGPPublicKey key = null;
|
// TODO
|
||||||
for (int i = 0; i < mPublicKeyRings.size(); ++i) {
|
|
||||||
PGPPublicKeyRing keyRing = mPublicKeyRings.get(i);
|
|
||||||
try {
|
|
||||||
key = keyRing.getPublicKey(keyId);
|
|
||||||
if (key != null) {
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
} catch (PGPException e) {
|
|
||||||
// just not found, can ignore this
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PGPSecretKey findSecretKey(long keyId) {
|
public static PGPPublicKeyRing getPublicKeyRing(long keyId) {
|
||||||
PGPSecretKey key = null;
|
// TODO
|
||||||
for (int i = 0; i < mSecretKeyRings.size(); ++i) {
|
|
||||||
PGPSecretKeyRing keyRing = mSecretKeyRings.get(i);
|
|
||||||
key = keyRing.getSecretKey(keyId);
|
|
||||||
if (key != null) {
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PGPSecretKeyRing findSecretKeyRing(long keyId) {
|
public static PGPSecretKey getSecretKey(long keyId) {
|
||||||
for (int i = 0; i < mSecretKeyRings.size(); ++i) {
|
// TODO
|
||||||
PGPSecretKeyRing keyRing = mSecretKeyRings.get(i);
|
|
||||||
PGPSecretKey key = null;
|
|
||||||
key = keyRing.getSecretKey(keyId);
|
|
||||||
if (key != null) {
|
|
||||||
return keyRing;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PGPPublicKeyRing findPublicKeyRing(long keyId) {
|
public static PGPPublicKey getPublicKey(long keyId) {
|
||||||
for (int i = 0; i < mPublicKeyRings.size(); ++i) {
|
// TODO
|
||||||
PGPPublicKeyRing keyRing = mPublicKeyRings.get(i);
|
|
||||||
PGPPublicKey key = null;
|
|
||||||
try {
|
|
||||||
key = keyRing.getPublicKey(keyId);
|
|
||||||
if (key != null) {
|
|
||||||
return keyRing;
|
|
||||||
}
|
|
||||||
} catch (PGPException e) {
|
|
||||||
// key not found
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static PGPPublicKey getPublicMasterKey(long keyId) {
|
|
||||||
PGPPublicKey key = null;
|
|
||||||
for (int i = 0; i < mPublicKeyRings.size(); ++i) {
|
|
||||||
PGPPublicKeyRing keyRing = mPublicKeyRings.get(i);
|
|
||||||
try {
|
|
||||||
key = keyRing.getPublicKey(keyId);
|
|
||||||
if (key != null) {
|
|
||||||
return getMasterKey(keyRing);
|
|
||||||
}
|
|
||||||
} catch (PGPException e) {
|
|
||||||
// just not found, can ignore this
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1282,7 +1056,7 @@ public class Apg {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (signatureKeyId != 0) {
|
if (signatureKeyId != 0) {
|
||||||
signingKeyRing = findSecretKeyRing(signatureKeyId);
|
signingKeyRing = getSecretKeyRing(signatureKeyId);
|
||||||
signingKey = getSigningKey(signatureKeyId);
|
signingKey = getSigningKey(signatureKeyId);
|
||||||
if (signingKey == null) {
|
if (signingKey == null) {
|
||||||
throw new GeneralException(context.getString(R.string.error_signatureFailed));
|
throw new GeneralException(context.getString(R.string.error_signatureFailed));
|
||||||
@ -1398,7 +1172,7 @@ public class Apg {
|
|||||||
throw new GeneralException(context.getString(R.string.error_noSignatureKey));
|
throw new GeneralException(context.getString(R.string.error_noSignatureKey));
|
||||||
}
|
}
|
||||||
|
|
||||||
signingKeyRing = findSecretKeyRing(signatureKeyId);
|
signingKeyRing = getSecretKeyRing(signatureKeyId);
|
||||||
signingKey = getSigningKey(signatureKeyId);
|
signingKey = getSigningKey(signatureKeyId);
|
||||||
if (signingKey == null) {
|
if (signingKey == null) {
|
||||||
throw new GeneralException(context.getString(R.string.error_signatureFailed));
|
throw new GeneralException(context.getString(R.string.error_signatureFailed));
|
||||||
@ -1484,7 +1258,7 @@ public class Apg {
|
|||||||
if (obj instanceof PGPPublicKeyEncryptedData) {
|
if (obj instanceof PGPPublicKeyEncryptedData) {
|
||||||
gotAsymmetricEncryption = true;
|
gotAsymmetricEncryption = true;
|
||||||
PGPPublicKeyEncryptedData pbe = (PGPPublicKeyEncryptedData) obj;
|
PGPPublicKeyEncryptedData pbe = (PGPPublicKeyEncryptedData) obj;
|
||||||
secretKey = findSecretKey(pbe.getKeyID());
|
secretKey = getSecretKey(pbe.getKeyID());
|
||||||
if (secretKey != null) {
|
if (secretKey != null) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1594,7 +1368,7 @@ public class Apg {
|
|||||||
Object obj = it.next();
|
Object obj = it.next();
|
||||||
if (obj instanceof PGPPublicKeyEncryptedData) {
|
if (obj instanceof PGPPublicKeyEncryptedData) {
|
||||||
PGPPublicKeyEncryptedData encData = (PGPPublicKeyEncryptedData) obj;
|
PGPPublicKeyEncryptedData encData = (PGPPublicKeyEncryptedData) obj;
|
||||||
secretKey = findSecretKey(encData.getKeyID());
|
secretKey = getSecretKey(encData.getKeyID());
|
||||||
if (secretKey != null) {
|
if (secretKey != null) {
|
||||||
pbe = encData;
|
pbe = encData;
|
||||||
break;
|
break;
|
||||||
@ -1643,7 +1417,7 @@ public class Apg {
|
|||||||
PGPOnePassSignatureList sigList = (PGPOnePassSignatureList) dataChunk;
|
PGPOnePassSignatureList sigList = (PGPOnePassSignatureList) dataChunk;
|
||||||
for (int i = 0; i < sigList.size(); ++i) {
|
for (int i = 0; i < sigList.size(); ++i) {
|
||||||
signature = sigList.get(i);
|
signature = sigList.get(i);
|
||||||
signatureKey = findPublicKey(signature.getKeyID());
|
signatureKey = getPublicKey(signature.getKeyID());
|
||||||
if (signatureKeyId == 0) {
|
if (signatureKeyId == 0) {
|
||||||
signatureKeyId = signature.getKeyID();
|
signatureKeyId = signature.getKeyID();
|
||||||
}
|
}
|
||||||
@ -1653,7 +1427,7 @@ public class Apg {
|
|||||||
signatureIndex = i;
|
signatureIndex = i;
|
||||||
signatureKeyId = signature.getKeyID();
|
signatureKeyId = signature.getKeyID();
|
||||||
String userId = null;
|
String userId = null;
|
||||||
PGPPublicKeyRing sigKeyRing = findPublicKeyRing(signatureKeyId);
|
PGPPublicKeyRing sigKeyRing = getPublicKeyRing(signatureKeyId);
|
||||||
if (sigKeyRing != null) {
|
if (sigKeyRing != null) {
|
||||||
userId = getMainUserId(getMasterKey(sigKeyRing));
|
userId = getMainUserId(getMasterKey(sigKeyRing));
|
||||||
}
|
}
|
||||||
@ -1788,7 +1562,7 @@ public class Apg {
|
|||||||
PGPPublicKey signatureKey = null;
|
PGPPublicKey signatureKey = null;
|
||||||
for (int i = 0; i < sigList.size(); ++i) {
|
for (int i = 0; i < sigList.size(); ++i) {
|
||||||
signature = sigList.get(i);
|
signature = sigList.get(i);
|
||||||
signatureKey = findPublicKey(signature.getKeyID());
|
signatureKey = getPublicKey(signature.getKeyID());
|
||||||
if (signatureKeyId == 0) {
|
if (signatureKeyId == 0) {
|
||||||
signatureKeyId = signature.getKeyID();
|
signatureKeyId = signature.getKeyID();
|
||||||
}
|
}
|
||||||
@ -1797,7 +1571,7 @@ public class Apg {
|
|||||||
} else {
|
} else {
|
||||||
signatureKeyId = signature.getKeyID();
|
signatureKeyId = signature.getKeyID();
|
||||||
String userId = null;
|
String userId = null;
|
||||||
PGPPublicKeyRing sigKeyRing = findPublicKeyRing(signatureKeyId);
|
PGPPublicKeyRing sigKeyRing = getPublicKeyRing(signatureKeyId);
|
||||||
if (sigKeyRing != null) {
|
if (sigKeyRing != null) {
|
||||||
userId = getMainUserId(getMasterKey(sigKeyRing));
|
userId = getMainUserId(getMasterKey(sigKeyRing));
|
||||||
}
|
}
|
||||||
@ -1840,15 +1614,6 @@ public class Apg {
|
|||||||
return returnData;
|
return returnData;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Vector<PGPPublicKeyRing> getPublicKeyRings() {
|
|
||||||
return mPublicKeyRings;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Vector<PGPSecretKeyRing> getSecretKeyRings() {
|
|
||||||
return mSecretKeyRings;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// taken from ClearSignedFileProcessor in BC
|
// taken from ClearSignedFileProcessor in BC
|
||||||
private static int readInputLine(ByteArrayOutputStream bOut, InputStream fIn)
|
private static int readInputLine(ByteArrayOutputStream bOut, InputStream fIn)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
|
@ -47,7 +47,7 @@ public class AskForSecretKeyPassPhrase {
|
|||||||
secretKey = null;
|
secretKey = null;
|
||||||
alert.setMessage(context.getString(R.string.passPhraseForSymmetricEncryption));
|
alert.setMessage(context.getString(R.string.passPhraseForSymmetricEncryption));
|
||||||
} else {
|
} else {
|
||||||
secretKey = Apg.getMasterKey(Apg.findSecretKeyRing(secretKeyId));
|
secretKey = Apg.getSecretKey(secretKeyId);
|
||||||
if (secretKey == null) {
|
if (secretKey == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,7 @@ import android.content.DialogInterface;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.os.Environment;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
@ -68,7 +69,15 @@ public class BaseActivity extends Activity
|
|||||||
if (mPreferences == null) {
|
if (mPreferences == null) {
|
||||||
mPreferences = getPreferences(MODE_PRIVATE);
|
mPreferences = getPreferences(MODE_PRIVATE);
|
||||||
}
|
}
|
||||||
Apg.initialize(this);
|
|
||||||
|
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
|
||||||
|
File dir = new File(Constants.path.app_dir);
|
||||||
|
if (!dir.exists() && !dir.mkdirs()) {
|
||||||
|
// ignore this for now, it's not crucial
|
||||||
|
// that the directory doesn't exist at this point
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (mCacheTimer == null) {
|
if (mCacheTimer == null) {
|
||||||
setPassPhraseCacheTimer();
|
setPassPhraseCacheTimer();
|
||||||
}
|
}
|
||||||
|
@ -279,7 +279,7 @@ public class EncryptActivity extends BaseActivity {
|
|||||||
long signatureKeyId = extras.getLong("signatureKeyId");
|
long signatureKeyId = extras.getLong("signatureKeyId");
|
||||||
long encryptionKeyIds[] = extras.getLongArray("encryptionKeyIds");
|
long encryptionKeyIds[] = extras.getLongArray("encryptionKeyIds");
|
||||||
if (signatureKeyId != 0) {
|
if (signatureKeyId != 0) {
|
||||||
PGPSecretKeyRing keyRing = Apg.findSecretKeyRing(signatureKeyId);
|
PGPSecretKeyRing keyRing = Apg.getSecretKeyRing(signatureKeyId);
|
||||||
PGPSecretKey masterKey = null;
|
PGPSecretKey masterKey = null;
|
||||||
if (keyRing != null) {
|
if (keyRing != null) {
|
||||||
masterKey = Apg.getMasterKey(keyRing);
|
masterKey = Apg.getMasterKey(keyRing);
|
||||||
@ -295,7 +295,7 @@ public class EncryptActivity extends BaseActivity {
|
|||||||
if (encryptionKeyIds != null) {
|
if (encryptionKeyIds != null) {
|
||||||
Vector<Long> goodIds = new Vector<Long>();
|
Vector<Long> goodIds = new Vector<Long>();
|
||||||
for (int i = 0; i < encryptionKeyIds.length; ++i) {
|
for (int i = 0; i < encryptionKeyIds.length; ++i) {
|
||||||
PGPPublicKeyRing keyRing = Apg.findPublicKeyRing(encryptionKeyIds[i]);
|
PGPPublicKeyRing keyRing = Apg.getPublicKeyRing(encryptionKeyIds[i]);
|
||||||
PGPPublicKey masterKey = null;
|
PGPPublicKey masterKey = null;
|
||||||
if (keyRing == null) {
|
if (keyRing == null) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -80,6 +80,11 @@ public final class Id {
|
|||||||
public static final int export_keys = 0x21070002;
|
public static final int export_keys = 0x21070002;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static final class database {
|
||||||
|
public static final int type_public = 0;
|
||||||
|
public static final int type_secret = 1;
|
||||||
|
}
|
||||||
|
|
||||||
public static final class type {
|
public static final class type {
|
||||||
public static final int public_key = 0x21070001;
|
public static final int public_key = 0x21070001;
|
||||||
public static final int secret_key = 0x21070002;
|
public static final int secret_key = 0x21070002;
|
||||||
@ -87,11 +92,6 @@ public final class Id {
|
|||||||
public static final int key = 0x21070004;
|
public static final int key = 0x21070004;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final class database {
|
|
||||||
public static final int type_public = 0;
|
|
||||||
public static final int type_secret = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final class choice {
|
public static final class choice {
|
||||||
public static final class algorithm {
|
public static final class algorithm {
|
||||||
public static final int dsa = 0x21070001;
|
public static final int dsa = 0x21070001;
|
||||||
|
633
src/org/thialfihar/android/apg/KeyListActivity.java
Normal file
633
src/org/thialfihar/android/apg/KeyListActivity.java
Normal file
@ -0,0 +1,633 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
|
||||||
|
*
|
||||||
|
* 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 org.thialfihar.android.apg;
|
||||||
|
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Vector;
|
||||||
|
|
||||||
|
import org.bouncycastle2.openpgp.PGPException;
|
||||||
|
import org.thialfihar.android.apg.provider.Database;
|
||||||
|
import org.thialfihar.android.apg.provider.KeyRings;
|
||||||
|
import org.thialfihar.android.apg.provider.Keys;
|
||||||
|
import org.thialfihar.android.apg.provider.UserIds;
|
||||||
|
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.app.Dialog;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.Message;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.MenuItem;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.BaseExpandableListAdapter;
|
||||||
|
import android.widget.ExpandableListView;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import android.widget.Toast;
|
||||||
|
import android.widget.ExpandableListView.ExpandableListContextMenuInfo;
|
||||||
|
|
||||||
|
public class KeyListActivity extends BaseActivity {
|
||||||
|
protected ExpandableListView mList;
|
||||||
|
|
||||||
|
protected int mSelectedItem = -1;
|
||||||
|
protected int mTask = 0;
|
||||||
|
|
||||||
|
protected String mImportFilename = Constants.path.app_dir + "/";
|
||||||
|
protected String mExportFilename = Constants.path.app_dir + "/";
|
||||||
|
|
||||||
|
protected int mKeyType = Id.type.public_key;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.key_list);
|
||||||
|
|
||||||
|
mList = (ExpandableListView) findViewById(R.id.list);
|
||||||
|
mList.setAdapter(new KeyListAdapter(this));
|
||||||
|
registerForContextMenu(mList);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
|
switch (item.getItemId()) {
|
||||||
|
case Id.menu.option.import_keys: {
|
||||||
|
showDialog(Id.dialog.import_keys);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Id.menu.option.export_keys: {
|
||||||
|
showDialog(Id.dialog.export_keys);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
default: {
|
||||||
|
return super.onOptionsItemSelected(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onContextItemSelected(MenuItem menuItem) {
|
||||||
|
ExpandableListContextMenuInfo info = (ExpandableListContextMenuInfo) menuItem.getMenuInfo();
|
||||||
|
int type = ExpandableListView.getPackedPositionType(info.packedPosition);
|
||||||
|
int groupPosition = ExpandableListView.getPackedPositionGroup(info.packedPosition);
|
||||||
|
|
||||||
|
if (type != ExpandableListView.PACKED_POSITION_TYPE_GROUP) {
|
||||||
|
return super.onContextItemSelected(menuItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (menuItem.getItemId()) {
|
||||||
|
case Id.menu.export: {
|
||||||
|
mSelectedItem = groupPosition;
|
||||||
|
showDialog(Id.dialog.export_key);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Id.menu.delete: {
|
||||||
|
mSelectedItem = groupPosition;
|
||||||
|
showDialog(Id.dialog.delete_key);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
default: {
|
||||||
|
return super.onContextItemSelected(menuItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Dialog onCreateDialog(int id) {
|
||||||
|
boolean singleKeyExport = false;
|
||||||
|
|
||||||
|
switch (id) {
|
||||||
|
case Id.dialog.delete_key: {
|
||||||
|
final long keyId = ((KeyListAdapter) mList.getExpandableListAdapter()).getGroupId(mSelectedItem);
|
||||||
|
// TODO: String userId = Apg.getMainUserIdSafe(this, Apg.getMasterKey(keyRing));
|
||||||
|
String userId = "SOME KEY";
|
||||||
|
|
||||||
|
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||||
|
builder.setTitle(R.string.warning);
|
||||||
|
builder.setMessage(getString(mKeyType == Id.type.public_key ?
|
||||||
|
R.string.keyDeletionConfirmation :
|
||||||
|
R.string.secretKeyDeletionConfirmation, userId));
|
||||||
|
builder.setIcon(android.R.drawable.ic_dialog_alert);
|
||||||
|
builder.setPositiveButton(R.string.btn_delete,
|
||||||
|
new DialogInterface.OnClickListener() {
|
||||||
|
public void onClick(DialogInterface dialog, int id) {
|
||||||
|
deleteKey(keyId);
|
||||||
|
removeDialog(Id.dialog.delete_key);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
builder.setNegativeButton(android.R.string.cancel,
|
||||||
|
new DialogInterface.OnClickListener() {
|
||||||
|
public void onClick(DialogInterface dialog, int id) {
|
||||||
|
removeDialog(Id.dialog.delete_key);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return builder.create();
|
||||||
|
}
|
||||||
|
|
||||||
|
case Id.dialog.import_keys: {
|
||||||
|
return FileDialog.build(this, getString(R.string.title_importKeys),
|
||||||
|
getString(R.string.specifyFileToImportFrom),
|
||||||
|
mImportFilename,
|
||||||
|
new FileDialog.OnClickListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onOkClick(String filename) {
|
||||||
|
removeDialog(Id.dialog.import_keys);
|
||||||
|
mImportFilename = filename;
|
||||||
|
importKeys();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCancelClick() {
|
||||||
|
removeDialog(Id.dialog.import_keys);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getString(R.string.filemanager_titleOpen),
|
||||||
|
getString(R.string.filemanager_btnOpen),
|
||||||
|
Id.request.filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
case Id.dialog.export_key: {
|
||||||
|
singleKeyExport = true;
|
||||||
|
// break intentionally omitted, to use the Id.dialog.export_keys dialog
|
||||||
|
}
|
||||||
|
|
||||||
|
case Id.dialog.export_keys: {
|
||||||
|
String title = (singleKeyExport ?
|
||||||
|
getString(R.string.title_exportKey) :
|
||||||
|
getString(R.string.title_exportKeys));
|
||||||
|
|
||||||
|
final int thisDialogId = (singleKeyExport ? Id.dialog.export_key : Id.dialog.export_keys);
|
||||||
|
|
||||||
|
return FileDialog.build(this, title,
|
||||||
|
getString(R.string.specifyFileToExportTo),
|
||||||
|
mExportFilename,
|
||||||
|
new FileDialog.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onOkClick(String filename) {
|
||||||
|
removeDialog(thisDialogId);
|
||||||
|
mExportFilename = filename;
|
||||||
|
exportKeys();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCancelClick() {
|
||||||
|
removeDialog(thisDialogId);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getString(R.string.filemanager_titleSave),
|
||||||
|
getString(R.string.filemanager_btnSave),
|
||||||
|
Id.request.filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
default: {
|
||||||
|
return super.onCreateDialog(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void importKeys() {
|
||||||
|
showDialog(Id.dialog.importing);
|
||||||
|
mTask = Id.task.import_keys;
|
||||||
|
startThread();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void exportKeys() {
|
||||||
|
showDialog(Id.dialog.exporting);
|
||||||
|
mTask = Id.task.export_keys;
|
||||||
|
startThread();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
String error = null;
|
||||||
|
Bundle data = new Bundle();
|
||||||
|
Message msg = new Message();
|
||||||
|
|
||||||
|
String filename = null;
|
||||||
|
if (mTask == Id.task.import_keys) {
|
||||||
|
filename = mImportFilename;
|
||||||
|
} else {
|
||||||
|
filename = mExportFilename;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (mTask == Id.task.import_keys) {
|
||||||
|
data = Apg.importKeyRings(this, mKeyType, filename, this);
|
||||||
|
} else {
|
||||||
|
Vector<Object> keys = new Vector<Object>();
|
||||||
|
// TODO
|
||||||
|
/*
|
||||||
|
if (mSelectedItem == -1) {
|
||||||
|
for (PGPSecretKeyRing key : Apg.getSecretKeyRings()) {
|
||||||
|
keys.add(key);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
keys.add(Apg.getSecretKeyRings().get(mSelectedItem));
|
||||||
|
}
|
||||||
|
if (mSelectedItem == -1) {
|
||||||
|
for (PGPPublicKeyRing key : Apg.getPublicKeyRings()) {
|
||||||
|
keys.add(key);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
keys.add(Apg.getPublicKeyRings().get(mSelectedItem));
|
||||||
|
}*/
|
||||||
|
data = Apg.exportKeyRings(this, keys, filename, this);
|
||||||
|
}
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
error = getString(R.string.error_fileNotFound);
|
||||||
|
} catch (IOException e) {
|
||||||
|
error = "" + e;
|
||||||
|
} catch (PGPException e) {
|
||||||
|
error = "" + e;
|
||||||
|
} catch (Apg.GeneralException e) {
|
||||||
|
error = "" + e;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mTask == Id.task.import_keys) {
|
||||||
|
data.putInt("type", Id.message.import_done);
|
||||||
|
} else {
|
||||||
|
data.putInt("type", Id.message.export_done);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error != null) {
|
||||||
|
data.putString("error", error);
|
||||||
|
}
|
||||||
|
|
||||||
|
msg.setData(data);
|
||||||
|
sendMessage(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void deleteKey(long keyId) {
|
||||||
|
// TODO
|
||||||
|
//PGPPublicKeyRing keyRing = Apg.getPublicKeyRings().get(index);
|
||||||
|
//Apg.deleteKey(this, keyRing);
|
||||||
|
refreshList();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void refreshList() {
|
||||||
|
((KeyListAdapter) mList.getExpandableListAdapter()).notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void doneCallback(Message msg) {
|
||||||
|
super.doneCallback(msg);
|
||||||
|
|
||||||
|
Bundle data = msg.getData();
|
||||||
|
if (data != null) {
|
||||||
|
int type = data.getInt("type");
|
||||||
|
switch (type) {
|
||||||
|
case Id.message.import_done: {
|
||||||
|
removeDialog(Id.dialog.importing);
|
||||||
|
|
||||||
|
String error = data.getString("error");
|
||||||
|
if (error != null) {
|
||||||
|
Toast.makeText(KeyListActivity.this,
|
||||||
|
getString(R.string.errorMessage, data.getString("error")),
|
||||||
|
Toast.LENGTH_SHORT).show();
|
||||||
|
} else {
|
||||||
|
int added = data.getInt("added");
|
||||||
|
int updated = data.getInt("updated");
|
||||||
|
String message;
|
||||||
|
if (added > 0 && updated > 0) {
|
||||||
|
message = getString(R.string.keysAddedAndUpdated, added, updated);
|
||||||
|
} else if (added > 0) {
|
||||||
|
message = getString(R.string.keysAdded, added);
|
||||||
|
} else if (updated > 0) {
|
||||||
|
message = getString(R.string.keysUpdated, updated);
|
||||||
|
} else {
|
||||||
|
message = getString(R.string.noKeysAddedOrUpdated);
|
||||||
|
}
|
||||||
|
Toast.makeText(KeyListActivity.this, message,
|
||||||
|
Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
refreshList();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Id.message.export_done: {
|
||||||
|
removeDialog(Id.dialog.exporting);
|
||||||
|
|
||||||
|
String error = data.getString("error");
|
||||||
|
if (error != null) {
|
||||||
|
Toast.makeText(KeyListActivity.this,
|
||||||
|
getString(R.string.errorMessage, data.getString("error")),
|
||||||
|
Toast.LENGTH_SHORT).show();
|
||||||
|
} else {
|
||||||
|
int exported = data.getInt("exported");
|
||||||
|
String message;
|
||||||
|
if (exported == 1) {
|
||||||
|
message = getString(R.string.keyExported);
|
||||||
|
} else if (exported > 0) {
|
||||||
|
message = getString(R.string.keysExported);
|
||||||
|
} else{
|
||||||
|
message = getString(R.string.noKeysExported);
|
||||||
|
}
|
||||||
|
Toast.makeText(KeyListActivity.this, message,
|
||||||
|
Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected class KeyListAdapter extends BaseExpandableListAdapter {
|
||||||
|
private LayoutInflater mInflater;
|
||||||
|
private Vector<Vector<KeyChild>> mChildren;
|
||||||
|
private SQLiteDatabase mDatabase;
|
||||||
|
private Cursor mCursor;
|
||||||
|
|
||||||
|
private class KeyChild {
|
||||||
|
public static final int KEY = 0;
|
||||||
|
public static final int USER_ID = 1;
|
||||||
|
|
||||||
|
public int type;
|
||||||
|
public String userId;
|
||||||
|
public long keyId;
|
||||||
|
public boolean isMasterKey;
|
||||||
|
public int algorithm;
|
||||||
|
public int keySize;
|
||||||
|
public boolean canSign;
|
||||||
|
public boolean canEncrypt;
|
||||||
|
|
||||||
|
public KeyChild(long keyId, boolean isMasterKey, int algorithm, int keySize,
|
||||||
|
boolean canSign, boolean canEncrypt) {
|
||||||
|
this.keyId = keyId;
|
||||||
|
this.isMasterKey = isMasterKey;
|
||||||
|
this.algorithm = algorithm;
|
||||||
|
this.keySize = keySize;
|
||||||
|
this.canSign = canSign;
|
||||||
|
this.canEncrypt = canEncrypt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public KeyChild(String userId) {
|
||||||
|
type = USER_ID;
|
||||||
|
this.userId = userId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public KeyListAdapter(Context context) {
|
||||||
|
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||||
|
mDatabase = new Database(context).getReadableDatabase();
|
||||||
|
mCursor = mDatabase.query(
|
||||||
|
KeyRings.TABLE_NAME + " INNER JOIN " + Keys.TABLE_NAME + " ON " +
|
||||||
|
"(" + KeyRings.TABLE_NAME + "." + KeyRings._ID + " = " +
|
||||||
|
Keys.TABLE_NAME + "." + Keys.KEY_RING_ID + " AND " +
|
||||||
|
Keys.TABLE_NAME + "." + Keys.IS_MASTER_KEY + " = '1'" +
|
||||||
|
") " +
|
||||||
|
" INNER JOIN " + UserIds.TABLE_NAME + " ON " +
|
||||||
|
"(" + Keys.TABLE_NAME + "." + Keys._ID + " = " +
|
||||||
|
UserIds.TABLE_NAME + "." + UserIds.KEY_ID + " AND " +
|
||||||
|
UserIds.TABLE_NAME + "." + UserIds.RANK + " = '0') ",
|
||||||
|
new String[] {
|
||||||
|
KeyRings.TABLE_NAME + "." + KeyRings._ID, // 0
|
||||||
|
KeyRings.TABLE_NAME + "." + KeyRings.MASTER_KEY_ID, // 1
|
||||||
|
UserIds.TABLE_NAME + "." + UserIds.USER_ID, // 2
|
||||||
|
},
|
||||||
|
KeyRings.TABLE_NAME + "." + KeyRings.TYPE + " = ?",
|
||||||
|
new String[] { "" + (mKeyType == Id.type.public_key ?
|
||||||
|
Id.database.type_public :
|
||||||
|
Id.database.type_secret) },
|
||||||
|
null, null, null);
|
||||||
|
|
||||||
|
mChildren = new Vector<Vector<KeyChild>>();
|
||||||
|
for (int i = 0; i < mCursor.getCount(); ++i) {
|
||||||
|
mChildren.add(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void finalize() throws Throwable {
|
||||||
|
mCursor.close();
|
||||||
|
mDatabase.close();
|
||||||
|
super.finalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Vector<KeyChild> getChildrenOfGroup(int groupPosition) {
|
||||||
|
Vector<KeyChild> children = mChildren.get(groupPosition);
|
||||||
|
if (children != null) {
|
||||||
|
return children;
|
||||||
|
}
|
||||||
|
|
||||||
|
mCursor.moveToPosition(groupPosition);
|
||||||
|
children = new Vector<KeyChild>();
|
||||||
|
Cursor c = mDatabase.query(Keys.TABLE_NAME,
|
||||||
|
new String[] {
|
||||||
|
Keys._ID, // 0
|
||||||
|
Keys.KEY_ID, // 1
|
||||||
|
Keys.IS_MASTER_KEY, // 2
|
||||||
|
Keys.ALGORITHM, // 3
|
||||||
|
Keys.KEY_SIZE, // 4
|
||||||
|
Keys.CAN_SIGN, // 5
|
||||||
|
Keys.CAN_ENCRYPT, // 6
|
||||||
|
},
|
||||||
|
Keys.KEY_RING_ID + " = ?",
|
||||||
|
new String[] { mCursor.getString(0) },
|
||||||
|
null, null, Keys.RANK + " ASC");
|
||||||
|
|
||||||
|
long masterKeyId = -1;
|
||||||
|
for (int i = 0; i < c.getCount(); ++i) {
|
||||||
|
c.moveToPosition(i);
|
||||||
|
children.add(new KeyChild(c.getLong(1), c.getInt(2) == 1, c.getInt(3), c.getInt(4),
|
||||||
|
c.getInt(5) == 1, c.getInt(6) == 1));
|
||||||
|
if (i == 0) {
|
||||||
|
masterKeyId = c.getInt(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.close();
|
||||||
|
|
||||||
|
if (masterKeyId != -1) {
|
||||||
|
c = mDatabase.query(UserIds.TABLE_NAME,
|
||||||
|
new String[] {
|
||||||
|
UserIds.USER_ID, // 0
|
||||||
|
},
|
||||||
|
UserIds.KEY_ID + " = ?",
|
||||||
|
new String[] { "" + masterKeyId },
|
||||||
|
null, null, UserIds.RANK + " ASC");
|
||||||
|
|
||||||
|
for (int i = 0; i < c.getCount(); ++i) {
|
||||||
|
c.moveToPosition(i);
|
||||||
|
children.add(new KeyChild(c.getString(0)));
|
||||||
|
}
|
||||||
|
c.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
mChildren.set(groupPosition, children);
|
||||||
|
return children;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasStableIds() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isChildSelectable(int groupPosition, int childPosition) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getGroupCount() {
|
||||||
|
return mCursor.getCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getChild(int groupPosition, int childPosition) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getChildId(int groupPosition, int childPosition) {
|
||||||
|
return childPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getChildrenCount(int groupPosition) {
|
||||||
|
return getChildrenOfGroup(groupPosition).size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getGroup(int position) {
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getGroupId(int position) {
|
||||||
|
mCursor.moveToPosition(position);
|
||||||
|
return mCursor.getLong(1); // MASTER_KEY_ID
|
||||||
|
}
|
||||||
|
|
||||||
|
public View getGroupView(int groupPosition, boolean isExpanded, View convertView,
|
||||||
|
ViewGroup parent) {
|
||||||
|
mCursor.moveToPosition(groupPosition);
|
||||||
|
|
||||||
|
View view = mInflater.inflate(R.layout.key_list_group_item, null);
|
||||||
|
view.setBackgroundResource(android.R.drawable.list_selector_background);
|
||||||
|
|
||||||
|
TextView mainUserId = (TextView) view.findViewById(R.id.mainUserId);
|
||||||
|
mainUserId.setText("");
|
||||||
|
TextView mainUserIdRest = (TextView) view.findViewById(R.id.mainUserIdRest);
|
||||||
|
mainUserIdRest.setText("");
|
||||||
|
|
||||||
|
String userId = mCursor.getString(2); // USER_ID
|
||||||
|
if (userId != null) {
|
||||||
|
String chunks[] = userId.split(" <", 2);
|
||||||
|
userId = chunks[0];
|
||||||
|
if (chunks.length > 1) {
|
||||||
|
mainUserIdRest.setText("<" + chunks[1]);
|
||||||
|
}
|
||||||
|
mainUserId.setText(userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mainUserId.getText().length() == 0) {
|
||||||
|
mainUserId.setText(R.string.unknownUserId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mainUserIdRest.getText().length() == 0) {
|
||||||
|
mainUserIdRest.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
public View getChildView(int groupPosition, int childPosition,
|
||||||
|
boolean isLastChild, View convertView,
|
||||||
|
ViewGroup parent) {
|
||||||
|
mCursor.moveToPosition(groupPosition);
|
||||||
|
|
||||||
|
Vector<KeyChild> children = getChildrenOfGroup(groupPosition);
|
||||||
|
|
||||||
|
KeyChild child = children.get(childPosition);
|
||||||
|
View view = null;
|
||||||
|
switch (child.type) {
|
||||||
|
case KeyChild.KEY: {
|
||||||
|
if (child.isMasterKey) {
|
||||||
|
view = mInflater.inflate(R.layout.key_list_child_item_master_key, null);
|
||||||
|
} else {
|
||||||
|
view = mInflater.inflate(R.layout.key_list_child_item_sub_key, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
TextView keyId = (TextView) view.findViewById(R.id.keyId);
|
||||||
|
String keyIdStr = Long.toHexString(child.keyId & 0xffffffffL);
|
||||||
|
while (keyIdStr.length() < 8) {
|
||||||
|
keyIdStr = "0" + keyIdStr;
|
||||||
|
}
|
||||||
|
keyId.setText(keyIdStr);
|
||||||
|
TextView keyDetails = (TextView) view.findViewById(R.id.keyDetails);
|
||||||
|
String algorithmStr = Apg.getAlgorithmInfo(child.algorithm, child.keySize);
|
||||||
|
keyDetails.setText("(" + algorithmStr + ")");
|
||||||
|
|
||||||
|
ImageView encryptIcon = (ImageView) view.findViewById(R.id.ic_encryptKey);
|
||||||
|
if (!child.canEncrypt) {
|
||||||
|
encryptIcon.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageView signIcon = (ImageView) view.findViewById(R.id.ic_signKey);
|
||||||
|
if (!child.canSign) {
|
||||||
|
signIcon.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case KeyChild.USER_ID: {
|
||||||
|
view = mInflater.inflate(R.layout.key_list_child_item_user_id, null);
|
||||||
|
TextView userId = (TextView) view.findViewById(R.id.userId);
|
||||||
|
userId.setText(child.userId);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
|
switch (requestCode) {
|
||||||
|
case Id.request.filename: {
|
||||||
|
if (resultCode == RESULT_OK && data != null) {
|
||||||
|
String filename = data.getDataString();
|
||||||
|
if (filename != null) {
|
||||||
|
// Get rid of URI prefix:
|
||||||
|
if (filename.startsWith("file://")) {
|
||||||
|
filename = filename.substring(7);
|
||||||
|
}
|
||||||
|
// replace %20 and so on
|
||||||
|
filename = Uri.decode(filename);
|
||||||
|
|
||||||
|
FileDialog.setFilename(filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
default: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
|
}
|
||||||
|
}
|
@ -16,54 +16,19 @@
|
|||||||
|
|
||||||
package org.thialfihar.android.apg;
|
package org.thialfihar.android.apg;
|
||||||
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Vector;
|
|
||||||
|
|
||||||
import org.bouncycastle2.openpgp.PGPException;
|
|
||||||
import org.bouncycastle2.openpgp.PGPPublicKey;
|
|
||||||
import org.bouncycastle2.openpgp.PGPPublicKeyRing;
|
|
||||||
import org.thialfihar.android.apg.utils.IterableIterator;
|
|
||||||
|
|
||||||
import android.app.AlertDialog;
|
|
||||||
import android.app.Dialog;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.DialogInterface;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Message;
|
|
||||||
import android.view.ContextMenu;
|
import android.view.ContextMenu;
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuItem;
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.view.ContextMenu.ContextMenuInfo;
|
import android.view.ContextMenu.ContextMenuInfo;
|
||||||
import android.widget.BaseExpandableListAdapter;
|
|
||||||
import android.widget.ExpandableListView;
|
import android.widget.ExpandableListView;
|
||||||
import android.widget.ImageView;
|
|
||||||
import android.widget.TextView;
|
|
||||||
import android.widget.Toast;
|
|
||||||
import android.widget.ExpandableListView.ExpandableListContextMenuInfo;
|
|
||||||
|
|
||||||
public class PublicKeyListActivity extends BaseActivity {
|
|
||||||
ExpandableListView mList;
|
|
||||||
|
|
||||||
protected int mSelectedItem = -1;
|
|
||||||
protected int mTask = 0;
|
|
||||||
|
|
||||||
private String mImportFilename = Constants.path.app_dir + "/";
|
|
||||||
private String mExportFilename = Constants.path.app_dir + "/pubexport.asc";
|
|
||||||
|
|
||||||
|
public class PublicKeyListActivity extends KeyListActivity {
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
|
mExportFilename = Constants.path.app_dir + "/pubexport.asc";
|
||||||
|
mKeyType = Id.type.public_key;
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setContentView(R.layout.key_list);
|
|
||||||
|
|
||||||
mList = (ExpandableListView) findViewById(R.id.list);
|
|
||||||
mList.setAdapter(new PublicKeyListAdapter(this));
|
|
||||||
registerForContextMenu(mList);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -79,507 +44,17 @@ public class PublicKeyListActivity extends BaseActivity {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onOptionsItemSelected(MenuItem item) {
|
|
||||||
switch (item.getItemId()) {
|
|
||||||
case Id.menu.option.import_keys: {
|
|
||||||
showDialog(Id.dialog.import_keys);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
case Id.menu.option.export_keys: {
|
|
||||||
showDialog(Id.dialog.export_keys);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
default: {
|
|
||||||
return super.onOptionsItemSelected(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
|
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
|
||||||
super.onCreateContextMenu(menu, v, menuInfo);
|
super.onCreateContextMenu(menu, v, menuInfo);
|
||||||
ExpandableListView.ExpandableListContextMenuInfo info =
|
ExpandableListView.ExpandableListContextMenuInfo info =
|
||||||
(ExpandableListView.ExpandableListContextMenuInfo) menuInfo;
|
(ExpandableListView.ExpandableListContextMenuInfo) menuInfo;
|
||||||
int type = ExpandableListView.getPackedPositionType(info.packedPosition);
|
int type = ExpandableListView.getPackedPositionType(info.packedPosition);
|
||||||
int groupPosition = ExpandableListView.getPackedPositionGroup(info.packedPosition);
|
|
||||||
|
|
||||||
if (type == ExpandableListView.PACKED_POSITION_TYPE_GROUP) {
|
if (type == ExpandableListView.PACKED_POSITION_TYPE_GROUP) {
|
||||||
PGPPublicKeyRing keyRing = Apg.getPublicKeyRings().get(groupPosition);
|
// TODO: user id? menu.setHeaderTitle("Key");
|
||||||
String userId = Apg.getMainUserIdSafe(this, Apg.getMasterKey(keyRing));
|
|
||||||
menu.setHeaderTitle(userId);
|
|
||||||
menu.add(0, Id.menu.export, 0, R.string.menu_exportKey);
|
menu.add(0, Id.menu.export, 0, R.string.menu_exportKey);
|
||||||
menu.add(0, Id.menu.delete, 1, R.string.menu_deleteKey);
|
menu.add(0, Id.menu.delete, 1, R.string.menu_deleteKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onContextItemSelected(MenuItem menuItem) {
|
|
||||||
ExpandableListContextMenuInfo info = (ExpandableListContextMenuInfo) menuItem.getMenuInfo();
|
|
||||||
int type = ExpandableListView.getPackedPositionType(info.packedPosition);
|
|
||||||
int groupPosition = ExpandableListView.getPackedPositionGroup(info.packedPosition);
|
|
||||||
|
|
||||||
if (type != ExpandableListView.PACKED_POSITION_TYPE_GROUP) {
|
|
||||||
return super.onContextItemSelected(menuItem);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (menuItem.getItemId()) {
|
|
||||||
case Id.menu.export: {
|
|
||||||
mSelectedItem = groupPosition;
|
|
||||||
showDialog(Id.dialog.export_key);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
case Id.menu.delete: {
|
|
||||||
mSelectedItem = groupPosition;
|
|
||||||
showDialog(Id.dialog.delete_key);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
default: {
|
|
||||||
return super.onContextItemSelected(menuItem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Dialog onCreateDialog(int id) {
|
|
||||||
boolean singleKeyExport = false;
|
|
||||||
|
|
||||||
switch (id) {
|
|
||||||
case Id.dialog.delete_key: {
|
|
||||||
PGPPublicKeyRing keyRing = Apg.getPublicKeyRings().get(mSelectedItem);
|
|
||||||
String userId = Apg.getMainUserIdSafe(this, Apg.getMasterKey(keyRing));
|
|
||||||
|
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
|
||||||
builder.setTitle(R.string.warning);
|
|
||||||
builder.setMessage(getString(R.string.keyDeletionConfirmation, userId));
|
|
||||||
builder.setIcon(android.R.drawable.ic_dialog_alert);
|
|
||||||
builder.setPositiveButton(R.string.btn_delete,
|
|
||||||
new DialogInterface.OnClickListener() {
|
|
||||||
public void onClick(DialogInterface dialog, int id) {
|
|
||||||
deleteKey(mSelectedItem);
|
|
||||||
mSelectedItem = -1;
|
|
||||||
removeDialog(Id.dialog.delete_key);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
builder.setNegativeButton(android.R.string.cancel,
|
|
||||||
new DialogInterface.OnClickListener() {
|
|
||||||
public void onClick(DialogInterface dialog, int id) {
|
|
||||||
mSelectedItem = -1;
|
|
||||||
removeDialog(Id.dialog.delete_key);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return builder.create();
|
|
||||||
}
|
|
||||||
|
|
||||||
case Id.dialog.import_keys: {
|
|
||||||
return FileDialog.build(this, getString(R.string.title_importKeys),
|
|
||||||
getString(R.string.specifyFileToImportFrom),
|
|
||||||
mImportFilename,
|
|
||||||
new FileDialog.OnClickListener() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onOkClick(String filename) {
|
|
||||||
removeDialog(Id.dialog.import_keys);
|
|
||||||
mImportFilename = filename;
|
|
||||||
importKeys();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCancelClick() {
|
|
||||||
removeDialog(Id.dialog.import_keys);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
getString(R.string.filemanager_titleOpen),
|
|
||||||
getString(R.string.filemanager_btnOpen),
|
|
||||||
Id.request.filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
case Id.dialog.export_key: {
|
|
||||||
singleKeyExport = true;
|
|
||||||
// break intentionally omitted, to use the Id.dialog.export_keys dialog
|
|
||||||
}
|
|
||||||
|
|
||||||
case Id.dialog.export_keys: {
|
|
||||||
String title = (singleKeyExport ?
|
|
||||||
getString(R.string.title_exportKey) :
|
|
||||||
getString(R.string.title_exportKeys));
|
|
||||||
|
|
||||||
final int thisDialogId = (singleKeyExport ? Id.dialog.export_key : Id.dialog.export_keys);
|
|
||||||
|
|
||||||
return FileDialog.build(this, title,
|
|
||||||
getString(R.string.specifyFileToExportTo),
|
|
||||||
mExportFilename,
|
|
||||||
new FileDialog.OnClickListener() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onOkClick(String filename) {
|
|
||||||
removeDialog(thisDialogId);
|
|
||||||
mExportFilename = filename;
|
|
||||||
exportKeys();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCancelClick() {
|
|
||||||
removeDialog(thisDialogId);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
getString(R.string.filemanager_titleSave),
|
|
||||||
getString(R.string.filemanager_btnSave),
|
|
||||||
Id.request.filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
default: {
|
|
||||||
return super.onCreateDialog(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void importKeys() {
|
|
||||||
showDialog(Id.dialog.importing);
|
|
||||||
mTask = Id.task.import_keys;
|
|
||||||
startThread();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void exportKeys() {
|
|
||||||
showDialog(Id.dialog.exporting);
|
|
||||||
mTask = Id.task.export_keys;
|
|
||||||
startThread();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
String error = null;
|
|
||||||
Bundle data = new Bundle();
|
|
||||||
Message msg = new Message();
|
|
||||||
|
|
||||||
String filename = null;
|
|
||||||
if (mTask == Id.task.import_keys) {
|
|
||||||
filename = mImportFilename;
|
|
||||||
} else {
|
|
||||||
filename = mExportFilename;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (mTask == Id.task.import_keys) {
|
|
||||||
data = Apg.importKeyRings(this, Id.type.public_key, filename, this);
|
|
||||||
} else {
|
|
||||||
Vector<Object> keys = new Vector<Object>();
|
|
||||||
if (mSelectedItem == -1) {
|
|
||||||
for (PGPPublicKeyRing key : Apg.getPublicKeyRings()) {
|
|
||||||
keys.add(key);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
keys.add(Apg.getPublicKeyRings().get(mSelectedItem));
|
|
||||||
}
|
|
||||||
data = Apg.exportKeyRings(this, keys, filename, this);
|
|
||||||
}
|
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
error = getString(R.string.error_fileNotFound);
|
|
||||||
} catch (IOException e) {
|
|
||||||
error = "" + e;
|
|
||||||
} catch (PGPException e) {
|
|
||||||
error = "" + e;
|
|
||||||
} catch (Apg.GeneralException e) {
|
|
||||||
error = "" + e;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mTask == Id.task.import_keys) {
|
|
||||||
data.putInt("type", Id.message.import_done);
|
|
||||||
} else {
|
|
||||||
data.putInt("type", Id.message.export_done);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (error != null) {
|
|
||||||
data.putString("error", error);
|
|
||||||
}
|
|
||||||
|
|
||||||
msg.setData(data);
|
|
||||||
sendMessage(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void deleteKey(int index) {
|
|
||||||
PGPPublicKeyRing keyRing = Apg.getPublicKeyRings().get(index);
|
|
||||||
Apg.deleteKey(this, keyRing);
|
|
||||||
refreshList();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void refreshList() {
|
|
||||||
((PublicKeyListAdapter) mList.getExpandableListAdapter()).notifyDataSetChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void doneCallback(Message msg) {
|
|
||||||
super.doneCallback(msg);
|
|
||||||
|
|
||||||
Bundle data = msg.getData();
|
|
||||||
if (data != null) {
|
|
||||||
int type = data.getInt("type");
|
|
||||||
switch (type) {
|
|
||||||
case Id.message.import_done: {
|
|
||||||
removeDialog(Id.dialog.importing);
|
|
||||||
|
|
||||||
String error = data.getString("error");
|
|
||||||
if (error != null) {
|
|
||||||
Toast.makeText(PublicKeyListActivity.this,
|
|
||||||
getString(R.string.errorMessage, data.getString("error")),
|
|
||||||
Toast.LENGTH_SHORT).show();
|
|
||||||
} else {
|
|
||||||
int added = data.getInt("added");
|
|
||||||
int updated = data.getInt("updated");
|
|
||||||
String message;
|
|
||||||
if (added > 0 && updated > 0) {
|
|
||||||
message = getString(R.string.keysAddedAndUpdated, added, updated);
|
|
||||||
} else if (added > 0) {
|
|
||||||
message = getString(R.string.keysAdded, added);
|
|
||||||
} else if (updated > 0) {
|
|
||||||
message = getString(R.string.keysUpdated, updated);
|
|
||||||
} else {
|
|
||||||
message = getString(R.string.noKeysAddedOrUpdated);
|
|
||||||
}
|
|
||||||
Toast.makeText(PublicKeyListActivity.this, message,
|
|
||||||
Toast.LENGTH_SHORT).show();
|
|
||||||
}
|
|
||||||
refreshList();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case Id.message.export_done: {
|
|
||||||
removeDialog(Id.dialog.exporting);
|
|
||||||
|
|
||||||
String error = data.getString("error");
|
|
||||||
if (error != null) {
|
|
||||||
Toast.makeText(PublicKeyListActivity.this,
|
|
||||||
getString(R.string.errorMessage, data.getString("error")),
|
|
||||||
Toast.LENGTH_SHORT).show();
|
|
||||||
} else {
|
|
||||||
int exported = data.getInt("exported");
|
|
||||||
String message;
|
|
||||||
if (exported == 1) {
|
|
||||||
message = getString(R.string.keyExported);
|
|
||||||
} else if (exported > 0) {
|
|
||||||
message = getString(R.string.keysExported);
|
|
||||||
} else{
|
|
||||||
message = getString(R.string.noKeysExported);
|
|
||||||
}
|
|
||||||
Toast.makeText(PublicKeyListActivity.this, message,
|
|
||||||
Toast.LENGTH_SHORT).show();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default: {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class PublicKeyListAdapter extends BaseExpandableListAdapter {
|
|
||||||
private LayoutInflater mInflater;
|
|
||||||
|
|
||||||
private class KeyChild {
|
|
||||||
public static final int KEY = 0;
|
|
||||||
public static final int USER_ID = 1;
|
|
||||||
|
|
||||||
public int type;
|
|
||||||
public PGPPublicKey key;
|
|
||||||
public String userId;
|
|
||||||
|
|
||||||
public KeyChild(PGPPublicKey key) {
|
|
||||||
type = KEY;
|
|
||||||
this.key = key;
|
|
||||||
}
|
|
||||||
|
|
||||||
public KeyChild(String userId) {
|
|
||||||
type = USER_ID;
|
|
||||||
this.userId = userId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public PublicKeyListAdapter(Context context) {
|
|
||||||
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Vector<KeyChild> getChildrenOfKeyRing(PGPPublicKeyRing keyRing) {
|
|
||||||
Vector<KeyChild> children = new Vector<KeyChild>();
|
|
||||||
PGPPublicKey masterKey = null;
|
|
||||||
for (PGPPublicKey key : new IterableIterator<PGPPublicKey>(keyRing.getPublicKeys())) {
|
|
||||||
children.add(new KeyChild(key));
|
|
||||||
if (key.isMasterKey()) {
|
|
||||||
masterKey = key;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (masterKey != null) {
|
|
||||||
boolean isFirst = true;
|
|
||||||
for (String userId : new IterableIterator<String>(masterKey.getUserIDs())) {
|
|
||||||
if (isFirst) {
|
|
||||||
// ignore first, it's in the group already
|
|
||||||
isFirst = false;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
children.add(new KeyChild(userId));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return children;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hasStableIds() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isChildSelectable(int groupPosition, int childPosition) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getGroupCount() {
|
|
||||||
return Apg.getPublicKeyRings().size();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object getChild(int groupPosition, int childPosition) {
|
|
||||||
PGPPublicKeyRing keyRing = Apg.getPublicKeyRings().get(groupPosition);
|
|
||||||
Vector<KeyChild> children = getChildrenOfKeyRing(keyRing);
|
|
||||||
|
|
||||||
KeyChild child = children.get(childPosition);
|
|
||||||
return child;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getChildId(int groupPosition, int childPosition) {
|
|
||||||
return childPosition;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getChildrenCount(int groupPosition) {
|
|
||||||
return getChildrenOfKeyRing(Apg.getPublicKeyRings().get(groupPosition)).size();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object getGroup(int position) {
|
|
||||||
return position;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getGroupId(int position) {
|
|
||||||
return position;
|
|
||||||
}
|
|
||||||
|
|
||||||
public View getGroupView(int groupPosition, boolean isExpanded, View convertView,
|
|
||||||
ViewGroup parent) {
|
|
||||||
PGPPublicKeyRing keyRing = Apg.getPublicKeyRings().get(groupPosition);
|
|
||||||
for (PGPPublicKey key : new IterableIterator<PGPPublicKey>(keyRing.getPublicKeys())) {
|
|
||||||
View view;
|
|
||||||
if (!key.isMasterKey()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
view = mInflater.inflate(R.layout.key_list_group_item, null);
|
|
||||||
view.setBackgroundResource(android.R.drawable.list_selector_background);
|
|
||||||
|
|
||||||
TextView mainUserId = (TextView) view.findViewById(R.id.mainUserId);
|
|
||||||
mainUserId.setText("");
|
|
||||||
TextView mainUserIdRest = (TextView) view.findViewById(R.id.mainUserIdRest);
|
|
||||||
mainUserIdRest.setText("");
|
|
||||||
|
|
||||||
String userId = Apg.getMainUserId(key);
|
|
||||||
if (userId != null) {
|
|
||||||
String chunks[] = userId.split(" <", 2);
|
|
||||||
userId = chunks[0];
|
|
||||||
if (chunks.length > 1) {
|
|
||||||
mainUserIdRest.setText("<" + chunks[1]);
|
|
||||||
}
|
|
||||||
mainUserId.setText(userId);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mainUserId.getText().length() == 0) {
|
|
||||||
mainUserId.setText(R.string.unknownUserId);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mainUserIdRest.getText().length() == 0) {
|
|
||||||
mainUserIdRest.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
return view;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public View getChildView(int groupPosition, int childPosition,
|
|
||||||
boolean isLastChild, View convertView,
|
|
||||||
ViewGroup parent) {
|
|
||||||
PGPPublicKeyRing keyRing = Apg.getPublicKeyRings().get(groupPosition);
|
|
||||||
Vector<KeyChild> children = getChildrenOfKeyRing(keyRing);
|
|
||||||
|
|
||||||
KeyChild child = children.get(childPosition);
|
|
||||||
View view = null;
|
|
||||||
switch (child.type) {
|
|
||||||
case KeyChild.KEY: {
|
|
||||||
PGPPublicKey key = child.key;
|
|
||||||
if (key.isMasterKey()) {
|
|
||||||
view = mInflater.inflate(R.layout.key_list_child_item_master_key, null);
|
|
||||||
} else {
|
|
||||||
view = mInflater.inflate(R.layout.key_list_child_item_sub_key, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
TextView keyId = (TextView) view.findViewById(R.id.keyId);
|
|
||||||
String keyIdStr = Long.toHexString(key.getKeyID() & 0xffffffffL);
|
|
||||||
while (keyIdStr.length() < 8) {
|
|
||||||
keyIdStr = "0" + keyIdStr;
|
|
||||||
}
|
|
||||||
keyId.setText(keyIdStr);
|
|
||||||
TextView keyDetails = (TextView) view.findViewById(R.id.keyDetails);
|
|
||||||
String algorithmStr = Apg.getAlgorithmInfo(key);
|
|
||||||
keyDetails.setText("(" + algorithmStr + ")");
|
|
||||||
|
|
||||||
ImageView encryptIcon = (ImageView) view.findViewById(R.id.ic_encryptKey);
|
|
||||||
if (!Apg.isEncryptionKey(key)) {
|
|
||||||
encryptIcon.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
ImageView signIcon = (ImageView) view.findViewById(R.id.ic_signKey);
|
|
||||||
if (!Apg.isSigningKey(key)) {
|
|
||||||
signIcon.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case KeyChild.USER_ID: {
|
|
||||||
view = mInflater.inflate(R.layout.key_list_child_item_user_id, null);
|
|
||||||
TextView userId = (TextView) view.findViewById(R.id.userId);
|
|
||||||
userId.setText(child.userId);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return view;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
|
||||||
switch (requestCode) {
|
|
||||||
case Id.request.filename: {
|
|
||||||
if (resultCode == RESULT_OK && data != null) {
|
|
||||||
String filename = data.getDataString();
|
|
||||||
if (filename != null) {
|
|
||||||
// Get rid of URI prefix:
|
|
||||||
if (filename.startsWith("file://")) {
|
|
||||||
filename = filename.substring(7);
|
|
||||||
}
|
|
||||||
// replace %20 and so on
|
|
||||||
filename = Uri.decode(filename);
|
|
||||||
|
|
||||||
FileDialog.setFilename(filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
default: {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
super.onActivityResult(requestCode, resultCode, data);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -16,55 +16,24 @@
|
|||||||
|
|
||||||
package org.thialfihar.android.apg;
|
package org.thialfihar.android.apg;
|
||||||
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Vector;
|
|
||||||
|
|
||||||
import org.bouncycastle2.openpgp.PGPException;
|
|
||||||
import org.bouncycastle2.openpgp.PGPSecretKey;
|
|
||||||
import org.bouncycastle2.openpgp.PGPSecretKeyRing;
|
|
||||||
import org.thialfihar.android.apg.utils.IterableIterator;
|
|
||||||
|
|
||||||
import android.app.AlertDialog;
|
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.content.Context;
|
|
||||||
import android.content.DialogInterface;
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Message;
|
|
||||||
import android.view.ContextMenu;
|
import android.view.ContextMenu;
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.view.ContextMenu.ContextMenuInfo;
|
import android.view.ContextMenu.ContextMenuInfo;
|
||||||
import android.widget.BaseExpandableListAdapter;
|
|
||||||
import android.widget.ExpandableListView;
|
import android.widget.ExpandableListView;
|
||||||
import android.widget.ImageView;
|
|
||||||
import android.widget.TextView;
|
|
||||||
import android.widget.Toast;
|
|
||||||
import android.widget.ExpandableListView.ExpandableListContextMenuInfo;
|
import android.widget.ExpandableListView.ExpandableListContextMenuInfo;
|
||||||
import android.widget.ExpandableListView.OnChildClickListener;
|
import android.widget.ExpandableListView.OnChildClickListener;
|
||||||
|
|
||||||
public class SecretKeyListActivity extends BaseActivity implements OnChildClickListener {
|
public class SecretKeyListActivity extends KeyListActivity implements OnChildClickListener {
|
||||||
ExpandableListView mList;
|
|
||||||
|
|
||||||
protected int mSelectedItem = -1;
|
|
||||||
protected int mTask = 0;
|
|
||||||
|
|
||||||
private String mImportFilename = Constants.path.app_dir + "/";
|
|
||||||
private String mExportFilename = Constants.path.app_dir + "/secexport.asc";
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
|
mExportFilename = Constants.path.app_dir + "/secexport.asc";
|
||||||
|
mKeyType = Id.type.secret_key;
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setContentView(R.layout.key_list);
|
|
||||||
|
|
||||||
mList = (ExpandableListView) findViewById(R.id.list);
|
|
||||||
mList.setAdapter(new SecretKeyListAdapter(this));
|
|
||||||
registerForContextMenu(mList);
|
|
||||||
mList.setOnChildClickListener(this);
|
mList.setOnChildClickListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,16 +55,6 @@ public class SecretKeyListActivity extends BaseActivity implements OnChildClickL
|
|||||||
@Override
|
@Override
|
||||||
public boolean onOptionsItemSelected(MenuItem item) {
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
switch (item.getItemId()) {
|
switch (item.getItemId()) {
|
||||||
case Id.menu.option.import_keys: {
|
|
||||||
showDialog(Id.dialog.import_keys);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
case Id.menu.option.export_keys: {
|
|
||||||
showDialog(Id.dialog.export_keys);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
case Id.menu.option.create: {
|
case Id.menu.option.create: {
|
||||||
createKey();
|
createKey();
|
||||||
return true;
|
return true;
|
||||||
@ -113,12 +72,9 @@ public class SecretKeyListActivity extends BaseActivity implements OnChildClickL
|
|||||||
ExpandableListView.ExpandableListContextMenuInfo info =
|
ExpandableListView.ExpandableListContextMenuInfo info =
|
||||||
(ExpandableListView.ExpandableListContextMenuInfo) menuInfo;
|
(ExpandableListView.ExpandableListContextMenuInfo) menuInfo;
|
||||||
int type = ExpandableListView.getPackedPositionType(info.packedPosition);
|
int type = ExpandableListView.getPackedPositionType(info.packedPosition);
|
||||||
int groupPosition = ExpandableListView.getPackedPositionGroup(info.packedPosition);
|
|
||||||
|
|
||||||
if (type == ExpandableListView.PACKED_POSITION_TYPE_GROUP) {
|
if (type == ExpandableListView.PACKED_POSITION_TYPE_GROUP) {
|
||||||
PGPSecretKeyRing keyRing = Apg.getSecretKeyRings().get(groupPosition);
|
// TODO: user id? menu.setHeaderTitle("Key");
|
||||||
String userId = Apg.getMainUserIdSafe(this, Apg.getMasterKey(keyRing));
|
|
||||||
menu.setHeaderTitle(userId);
|
|
||||||
menu.add(0, Id.menu.edit, 0, R.string.menu_editKey);
|
menu.add(0, Id.menu.edit, 0, R.string.menu_editKey);
|
||||||
menu.add(0, Id.menu.export, 1, R.string.menu_exportKey);
|
menu.add(0, Id.menu.export, 1, R.string.menu_exportKey);
|
||||||
menu.add(0, Id.menu.delete, 2, R.string.menu_deleteKey);
|
menu.add(0, Id.menu.delete, 2, R.string.menu_deleteKey);
|
||||||
@ -142,18 +98,6 @@ public class SecretKeyListActivity extends BaseActivity implements OnChildClickL
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
case Id.menu.export: {
|
|
||||||
mSelectedItem = groupPosition;
|
|
||||||
showDialog(Id.dialog.export_key);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
case Id.menu.delete: {
|
|
||||||
mSelectedItem = groupPosition;
|
|
||||||
showDialog(Id.dialog.delete_key);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
return super.onContextItemSelected(menuItem);
|
return super.onContextItemSelected(menuItem);
|
||||||
}
|
}
|
||||||
@ -170,96 +114,9 @@ public class SecretKeyListActivity extends BaseActivity implements OnChildClickL
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Dialog onCreateDialog(int id) {
|
protected Dialog onCreateDialog(int id) {
|
||||||
boolean singleKeyExport = false;
|
|
||||||
|
|
||||||
switch (id) {
|
switch (id) {
|
||||||
case Id.dialog.delete_key: {
|
|
||||||
PGPSecretKeyRing keyRing = Apg.getSecretKeyRings().get(mSelectedItem);
|
|
||||||
|
|
||||||
String userId = Apg.getMainUserIdSafe(this, Apg.getMasterKey(keyRing));
|
|
||||||
|
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
|
||||||
builder.setTitle(R.string.warning);
|
|
||||||
builder.setMessage(getString(R.string.secretKeyDeletionConfirmation, userId));
|
|
||||||
builder.setIcon(android.R.drawable.ic_dialog_alert);
|
|
||||||
builder.setPositiveButton(R.string.btn_delete,
|
|
||||||
new DialogInterface.OnClickListener() {
|
|
||||||
public void onClick(DialogInterface dialog, int id) {
|
|
||||||
deleteKey(mSelectedItem);
|
|
||||||
mSelectedItem = -1;
|
|
||||||
removeDialog(Id.dialog.delete_key);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
builder.setNegativeButton(android.R.string.ok,
|
|
||||||
new DialogInterface.OnClickListener() {
|
|
||||||
public void onClick(DialogInterface dialog, int id) {
|
|
||||||
mSelectedItem = -1;
|
|
||||||
removeDialog(Id.dialog.delete_key);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return builder.create();
|
|
||||||
}
|
|
||||||
|
|
||||||
case Id.dialog.import_keys: {
|
|
||||||
return FileDialog.build(this, getString(R.string.title_importKeys),
|
|
||||||
getString(R.string.specifyFileToImportFrom),
|
|
||||||
mImportFilename,
|
|
||||||
new FileDialog.OnClickListener() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onOkClick(String filename) {
|
|
||||||
removeDialog(Id.dialog.import_keys);
|
|
||||||
mImportFilename = filename;
|
|
||||||
importKeys();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCancelClick() {
|
|
||||||
removeDialog(Id.dialog.import_keys);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
getString(R.string.filemanager_titleOpen),
|
|
||||||
getString(R.string.filemanager_btnOpen),
|
|
||||||
Id.request.filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
case Id.dialog.export_key: {
|
|
||||||
singleKeyExport = true;
|
|
||||||
// break intentionally omitted, to use the Id.dialog.export_keys dialog
|
|
||||||
}
|
|
||||||
|
|
||||||
case Id.dialog.export_keys: {
|
|
||||||
String title = (singleKeyExport ?
|
|
||||||
getString(R.string.title_exportKey) :
|
|
||||||
getString(R.string.title_exportKeys));
|
|
||||||
|
|
||||||
final int thisDialogId = (singleKeyExport ? Id.dialog.export_key : Id.dialog.export_keys);
|
|
||||||
|
|
||||||
return FileDialog.build(this, title,
|
|
||||||
getString(R.string.specifyFileToExportSecretKeysTo),
|
|
||||||
mExportFilename,
|
|
||||||
new FileDialog.OnClickListener() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onOkClick(String filename) {
|
|
||||||
removeDialog(thisDialogId);
|
|
||||||
mExportFilename = filename;
|
|
||||||
exportKeys();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCancelClick() {
|
|
||||||
removeDialog(thisDialogId);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
getString(R.string.filemanager_titleSave),
|
|
||||||
getString(R.string.filemanager_btnSave),
|
|
||||||
Id.request.filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
case Id.dialog.pass_phrase: {
|
case Id.dialog.pass_phrase: {
|
||||||
PGPSecretKeyRing keyRing = Apg.getSecretKeyRings().get(mSelectedItem);
|
long keyId = ((KeyListAdapter) mList.getExpandableListAdapter()).getGroupId(mSelectedItem);
|
||||||
long keyId = keyRing.getSecretKey().getKeyID();
|
|
||||||
return AskForSecretKeyPassPhrase.createDialog(this, keyId, this);
|
return AskForSecretKeyPassPhrase.createDialog(this, keyId, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -270,8 +127,7 @@ public class SecretKeyListActivity extends BaseActivity implements OnChildClickL
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void checkPassPhraseAndEdit() {
|
public void checkPassPhraseAndEdit() {
|
||||||
PGPSecretKeyRing keyRing = Apg.getSecretKeyRings().get(mSelectedItem);
|
long keyId = ((KeyListAdapter) mList.getExpandableListAdapter()).getGroupId(mSelectedItem);
|
||||||
long keyId = keyRing.getSecretKey().getKeyID();
|
|
||||||
String passPhrase = Apg.getCachedPassPhrase(keyId);
|
String passPhrase = Apg.getCachedPassPhrase(keyId);
|
||||||
if (passPhrase == null) {
|
if (passPhrase == null) {
|
||||||
showDialog(Id.dialog.pass_phrase);
|
showDialog(Id.dialog.pass_phrase);
|
||||||
@ -295,8 +151,7 @@ public class SecretKeyListActivity extends BaseActivity implements OnChildClickL
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void editKey() {
|
private void editKey() {
|
||||||
PGPSecretKeyRing keyRing = Apg.getSecretKeyRings().get(mSelectedItem);
|
long keyId = ((KeyListAdapter) mList.getExpandableListAdapter()).getGroupId(mSelectedItem);
|
||||||
long keyId = keyRing.getSecretKey().getKeyID();
|
|
||||||
Intent intent = new Intent(this, EditKeyActivity.class);
|
Intent intent = new Intent(this, EditKeyActivity.class);
|
||||||
intent.putExtra("keyId", keyId);
|
intent.putExtra("keyId", keyId);
|
||||||
startActivityForResult(intent, Id.message.edit_key);
|
startActivityForResult(intent, Id.message.edit_key);
|
||||||
@ -313,24 +168,6 @@ public class SecretKeyListActivity extends BaseActivity implements OnChildClickL
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case Id.request.filename: {
|
|
||||||
if (resultCode == RESULT_OK && data != null) {
|
|
||||||
String filename = data.getDataString();
|
|
||||||
if (filename != null) {
|
|
||||||
// Get rid of URI prefix:
|
|
||||||
if (filename.startsWith("file://")) {
|
|
||||||
filename = filename.substring(7);
|
|
||||||
}
|
|
||||||
// replace %20 and so on
|
|
||||||
filename = Uri.decode(filename);
|
|
||||||
|
|
||||||
FileDialog.setFilename(filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -338,320 +175,4 @@ public class SecretKeyListActivity extends BaseActivity implements OnChildClickL
|
|||||||
|
|
||||||
super.onActivityResult(requestCode, resultCode, data);
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void importKeys() {
|
|
||||||
showDialog(Id.dialog.importing);
|
|
||||||
mTask = Id.task.import_keys;
|
|
||||||
startThread();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void exportKeys() {
|
|
||||||
showDialog(Id.dialog.exporting);
|
|
||||||
mTask = Id.task.export_keys;
|
|
||||||
startThread();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
String error = null;
|
|
||||||
Bundle data = new Bundle();
|
|
||||||
Message msg = new Message();
|
|
||||||
|
|
||||||
String filename = null;
|
|
||||||
if (mTask == Id.task.import_keys) {
|
|
||||||
filename = mImportFilename;
|
|
||||||
} else {
|
|
||||||
filename = mExportFilename;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (mTask == Id.task.import_keys) {
|
|
||||||
data = Apg.importKeyRings(this, Id.type.secret_key, filename, this);
|
|
||||||
} else {
|
|
||||||
Vector<Object> keys = new Vector<Object>();
|
|
||||||
if (mSelectedItem == -1) {
|
|
||||||
for (PGPSecretKeyRing key : Apg.getSecretKeyRings()) {
|
|
||||||
keys.add(key);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
keys.add(Apg.getSecretKeyRings().get(mSelectedItem));
|
|
||||||
}
|
|
||||||
data = Apg.exportKeyRings(this, keys, filename, this);
|
|
||||||
}
|
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
error = getString(R.string.error_fileNotFound);
|
|
||||||
} catch (IOException e) {
|
|
||||||
error = "" + e;
|
|
||||||
} catch (PGPException e) {
|
|
||||||
error = "" + e;
|
|
||||||
} catch (Apg.GeneralException e) {
|
|
||||||
error = "" + e;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mTask == Id.task.import_keys) {
|
|
||||||
data.putInt("type", Id.message.import_done);
|
|
||||||
} else {
|
|
||||||
data.putInt("type", Id.message.export_done);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (error != null) {
|
|
||||||
data.putString("error", error);
|
|
||||||
}
|
|
||||||
|
|
||||||
msg.setData(data);
|
|
||||||
sendMessage(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void deleteKey(int index) {
|
|
||||||
PGPSecretKeyRing keyRing = Apg.getSecretKeyRings().get(index);
|
|
||||||
Apg.deleteKey(this, keyRing);
|
|
||||||
refreshList();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void refreshList() {
|
|
||||||
((SecretKeyListAdapter) mList.getExpandableListAdapter()).notifyDataSetChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void doneCallback(Message msg) {
|
|
||||||
super.doneCallback(msg);
|
|
||||||
|
|
||||||
Bundle data = msg.getData();
|
|
||||||
if (data != null) {
|
|
||||||
int type = data.getInt("type");
|
|
||||||
switch (type) {
|
|
||||||
case Id.message.import_done: {
|
|
||||||
removeDialog(Id.dialog.importing);
|
|
||||||
|
|
||||||
String error = data.getString("error");
|
|
||||||
if (error != null) {
|
|
||||||
Toast.makeText(SecretKeyListActivity.this,
|
|
||||||
getString(R.string.errorMessage, data.getString("error")),
|
|
||||||
Toast.LENGTH_SHORT).show();
|
|
||||||
} else {
|
|
||||||
int added = data.getInt("added");
|
|
||||||
int updated = data.getInt("updated");
|
|
||||||
String message;
|
|
||||||
if (added > 0 && updated > 0) {
|
|
||||||
message = getString(R.string.keysAddedAndUpdated, added, updated);
|
|
||||||
} else if (added > 0) {
|
|
||||||
message = getString(R.string.keysAdded, added);
|
|
||||||
} else if (updated > 0) {
|
|
||||||
message = getString(R.string.keysUpdated, updated);
|
|
||||||
} else {
|
|
||||||
message = getString(R.string.noKeysAddedOrUpdated);
|
|
||||||
}
|
|
||||||
Toast.makeText(SecretKeyListActivity.this, message,
|
|
||||||
Toast.LENGTH_SHORT).show();
|
|
||||||
}
|
|
||||||
refreshList();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case Id.message.export_done: {
|
|
||||||
removeDialog(Id.dialog.exporting);
|
|
||||||
|
|
||||||
String error = data.getString("error");
|
|
||||||
if (error != null) {
|
|
||||||
Toast.makeText(SecretKeyListActivity.this,
|
|
||||||
getString(R.string.errorMessage, data.getString("error")),
|
|
||||||
Toast.LENGTH_SHORT).show();
|
|
||||||
} else {
|
|
||||||
int exported = data.getInt("exported");
|
|
||||||
String message;
|
|
||||||
if (exported == 1) {
|
|
||||||
message = getString(R.string.keyExported);
|
|
||||||
} else if (exported > 0) {
|
|
||||||
message = getString(R.string.keysExported);
|
|
||||||
} else{
|
|
||||||
message = getString(R.string.noKeysExported);
|
|
||||||
}
|
|
||||||
Toast.makeText(SecretKeyListActivity.this, message,
|
|
||||||
Toast.LENGTH_SHORT).show();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default: {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class SecretKeyListAdapter extends BaseExpandableListAdapter {
|
|
||||||
private LayoutInflater mInflater;
|
|
||||||
|
|
||||||
private class KeyChild {
|
|
||||||
static final int KEY = 0;
|
|
||||||
static final int USER_ID = 1;
|
|
||||||
|
|
||||||
public int type;
|
|
||||||
public PGPSecretKey key;
|
|
||||||
public String userId;
|
|
||||||
|
|
||||||
public KeyChild(PGPSecretKey key) {
|
|
||||||
type = KEY;
|
|
||||||
this.key = key;
|
|
||||||
}
|
|
||||||
|
|
||||||
public KeyChild(String userId) {
|
|
||||||
type = USER_ID;
|
|
||||||
this.userId = userId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public SecretKeyListAdapter(Context context) {
|
|
||||||
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Vector<KeyChild> getChildrenOfKeyRing(PGPSecretKeyRing keyRing) {
|
|
||||||
Vector<KeyChild> children = new Vector<KeyChild>();
|
|
||||||
PGPSecretKey masterKey = null;
|
|
||||||
for (PGPSecretKey key : new IterableIterator<PGPSecretKey>(keyRing.getSecretKeys())) {
|
|
||||||
children.add(new KeyChild(key));
|
|
||||||
if (key.isMasterKey()) {
|
|
||||||
masterKey = key;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (masterKey != null) {
|
|
||||||
boolean isFirst = true;
|
|
||||||
for (String userId : new IterableIterator<String>(masterKey.getUserIDs())) {
|
|
||||||
if (isFirst) {
|
|
||||||
// ignore first, it's in the group already
|
|
||||||
isFirst = false;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
children.add(new KeyChild(userId));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return children;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hasStableIds() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isChildSelectable(int groupPosition, int childPosition) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getGroupCount() {
|
|
||||||
return Apg.getSecretKeyRings().size();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object getChild(int groupPosition, int childPosition) {
|
|
||||||
PGPSecretKeyRing keyRing = Apg.getSecretKeyRings().get(groupPosition);
|
|
||||||
Vector<KeyChild> children = getChildrenOfKeyRing(keyRing);
|
|
||||||
KeyChild child = children.get(childPosition);
|
|
||||||
return child;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getChildId(int groupPosition, int childPosition) {
|
|
||||||
return childPosition;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getChildrenCount(int groupPosition) {
|
|
||||||
return getChildrenOfKeyRing(Apg.getSecretKeyRings().get(groupPosition)).size();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object getGroup(int position) {
|
|
||||||
return position;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getGroupId(int position) {
|
|
||||||
return position;
|
|
||||||
}
|
|
||||||
|
|
||||||
public View getGroupView(int groupPosition, boolean isExpanded,
|
|
||||||
View convertView, ViewGroup parent) {
|
|
||||||
PGPSecretKeyRing keyRing = Apg.getSecretKeyRings().get(groupPosition);
|
|
||||||
for (PGPSecretKey key : new IterableIterator<PGPSecretKey>(keyRing.getSecretKeys())) {
|
|
||||||
View view;
|
|
||||||
if (!key.isMasterKey()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
view = mInflater.inflate(R.layout.key_list_group_item, null);
|
|
||||||
view.setBackgroundResource(android.R.drawable.list_selector_background);
|
|
||||||
|
|
||||||
TextView mainUserId = (TextView) view.findViewById(R.id.mainUserId);
|
|
||||||
mainUserId.setText("");
|
|
||||||
TextView mainUserIdRest = (TextView) view.findViewById(R.id.mainUserIdRest);
|
|
||||||
mainUserIdRest.setText("");
|
|
||||||
|
|
||||||
String userId = Apg.getMainUserId(key);
|
|
||||||
if (userId != null) {
|
|
||||||
String chunks[] = userId.split(" <", 2);
|
|
||||||
userId = chunks[0];
|
|
||||||
if (chunks.length > 1) {
|
|
||||||
mainUserIdRest.setText("<" + chunks[1]);
|
|
||||||
}
|
|
||||||
mainUserId.setText(userId);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mainUserId.getText().length() == 0) {
|
|
||||||
mainUserId.setText(R.string.unknownUserId);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mainUserIdRest.getText().length() == 0) {
|
|
||||||
mainUserIdRest.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
return view;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public View getChildView(int groupPosition, int childPosition,
|
|
||||||
boolean isLastChild, View convertView,
|
|
||||||
ViewGroup parent) {
|
|
||||||
PGPSecretKeyRing keyRing = Apg.getSecretKeyRings().get(groupPosition);
|
|
||||||
Vector<KeyChild> children = getChildrenOfKeyRing(keyRing);
|
|
||||||
|
|
||||||
KeyChild child = children.get(childPosition);
|
|
||||||
View view = null;
|
|
||||||
switch (child.type) {
|
|
||||||
case KeyChild.KEY: {
|
|
||||||
PGPSecretKey key = child.key;
|
|
||||||
if (key.isMasterKey()) {
|
|
||||||
view = mInflater.inflate(R.layout.key_list_child_item_master_key, null);
|
|
||||||
} else {
|
|
||||||
view = mInflater.inflate(R.layout.key_list_child_item_sub_key, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
TextView keyId = (TextView) view.findViewById(R.id.keyId);
|
|
||||||
String keyIdStr = Long.toHexString(key.getKeyID() & 0xffffffffL);
|
|
||||||
while (keyIdStr.length() < 8) {
|
|
||||||
keyIdStr = "0" + keyIdStr;
|
|
||||||
}
|
|
||||||
keyId.setText(keyIdStr);
|
|
||||||
TextView keyDetails = (TextView) view.findViewById(R.id.keyDetails);
|
|
||||||
String algorithmStr = Apg.getAlgorithmInfo(key);
|
|
||||||
keyDetails.setText("(" + algorithmStr + ")");
|
|
||||||
|
|
||||||
ImageView encryptIcon = (ImageView) view.findViewById(R.id.ic_encryptKey);
|
|
||||||
if (!Apg.isEncryptionKey(key)) {
|
|
||||||
encryptIcon.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
ImageView signIcon = (ImageView) view.findViewById(R.id.ic_signKey);
|
|
||||||
if (!Apg.isSigningKey(key)) {
|
|
||||||
signIcon.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case KeyChild.USER_ID: {
|
|
||||||
view = mInflater.inflate(R.layout.key_list_child_item_user_id, null);
|
|
||||||
TextView userId = (TextView) view.findViewById(R.id.userId);
|
|
||||||
userId.setText(child.userId);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return view;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -21,12 +21,10 @@ import java.util.HashMap;
|
|||||||
import android.content.ContentProvider;
|
import android.content.ContentProvider;
|
||||||
import android.content.ContentUris;
|
import android.content.ContentUris;
|
||||||
import android.content.ContentValues;
|
import android.content.ContentValues;
|
||||||
import android.content.Context;
|
|
||||||
import android.content.UriMatcher;
|
import android.content.UriMatcher;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.database.SQLException;
|
import android.database.SQLException;
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
import android.database.sqlite.SQLiteOpenHelper;
|
|
||||||
import android.database.sqlite.SQLiteQueryBuilder;
|
import android.database.sqlite.SQLiteQueryBuilder;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
@ -34,9 +34,9 @@ public class Database extends SQLiteOpenHelper {
|
|||||||
|
|
||||||
public static final String AUTHORITY = "org.thialfihar.android.apg.database";
|
public static final String AUTHORITY = "org.thialfihar.android.apg.database";
|
||||||
|
|
||||||
private static HashMap<String, String> sKeyRingsProjection;
|
public static HashMap<String, String> sKeyRingsProjection;
|
||||||
private static HashMap<String, String> sKeysProjection;
|
public static HashMap<String, String> sKeysProjection;
|
||||||
private static HashMap<String, String> sUserIdsProjection;
|
public static HashMap<String, String> sUserIdsProjection;
|
||||||
|
|
||||||
private SQLiteDatabase mCurrentDb = null;
|
private SQLiteDatabase mCurrentDb = null;
|
||||||
|
|
||||||
@ -67,11 +67,11 @@ public class Database extends SQLiteOpenHelper {
|
|||||||
sUserIdsProjection.put(UserIds.RANK, UserIds.RANK);
|
sUserIdsProjection.put(UserIds.RANK, UserIds.RANK);
|
||||||
}
|
}
|
||||||
|
|
||||||
Database(Context context) {
|
public Database(Context context) {
|
||||||
super(context, DATABASE_NAME, null, DATABASE_VERSION);
|
super(context, DATABASE_NAME, null, DATABASE_VERSION);
|
||||||
//getWritableDatabase();
|
//getWritableDatabase();
|
||||||
// force upgrade to test things
|
// force upgrade to test things
|
||||||
onUpgrade(getWritableDatabase(), 1, 2);
|
//onUpgrade(getWritableDatabase(), 1, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -161,6 +161,7 @@ public class Database extends SQLiteOpenHelper {
|
|||||||
}
|
}
|
||||||
} while (cursor.moveToNext());
|
} while (cursor.moveToNext());
|
||||||
}
|
}
|
||||||
|
cursor.close();
|
||||||
|
|
||||||
cursor = db.query(SecretKeys.TABLE_NAME,
|
cursor = db.query(SecretKeys.TABLE_NAME,
|
||||||
new String[]{
|
new String[]{
|
||||||
@ -182,6 +183,7 @@ public class Database extends SQLiteOpenHelper {
|
|||||||
}
|
}
|
||||||
} while (cursor.moveToNext());
|
} while (cursor.moveToNext());
|
||||||
}
|
}
|
||||||
|
cursor.close();
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -310,6 +312,7 @@ public class Database extends SQLiteOpenHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private long insertOrUpdateKeyRing(ContentValues values) {
|
private long insertOrUpdateKeyRing(ContentValues values) {
|
||||||
|
boolean grabbedNewDatabase = (mCurrentDb == null);
|
||||||
SQLiteDatabase db = mCurrentDb != null ? mCurrentDb : getWritableDatabase();
|
SQLiteDatabase db = mCurrentDb != null ? mCurrentDb : getWritableDatabase();
|
||||||
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
|
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
|
||||||
|
|
||||||
@ -332,10 +335,17 @@ public class Database extends SQLiteOpenHelper {
|
|||||||
rowId = db.insert(KeyRings.TABLE_NAME, KeyRings.WHO_ID, values);
|
rowId = db.insert(KeyRings.TABLE_NAME, KeyRings.WHO_ID, values);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
c.close();
|
||||||
|
|
||||||
|
if (grabbedNewDatabase) {
|
||||||
|
db.close();
|
||||||
|
}
|
||||||
|
|
||||||
return rowId;
|
return rowId;
|
||||||
}
|
}
|
||||||
|
|
||||||
private long insertOrUpdateKey(ContentValues values) {
|
private long insertOrUpdateKey(ContentValues values) {
|
||||||
|
boolean grabbedNewDatabase = (mCurrentDb == null);
|
||||||
SQLiteDatabase db = mCurrentDb != null ? mCurrentDb : getWritableDatabase();
|
SQLiteDatabase db = mCurrentDb != null ? mCurrentDb : getWritableDatabase();
|
||||||
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
|
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
|
||||||
|
|
||||||
@ -358,10 +368,17 @@ public class Database extends SQLiteOpenHelper {
|
|||||||
rowId = db.insert(Keys.TABLE_NAME, Keys.KEY_DATA, values);
|
rowId = db.insert(Keys.TABLE_NAME, Keys.KEY_DATA, values);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
c.close();
|
||||||
|
|
||||||
|
if (grabbedNewDatabase) {
|
||||||
|
db.close();
|
||||||
|
}
|
||||||
|
|
||||||
return rowId;
|
return rowId;
|
||||||
}
|
}
|
||||||
|
|
||||||
private long insertOrUpdateUserId(ContentValues values) {
|
private long insertOrUpdateUserId(ContentValues values) {
|
||||||
|
boolean grabbedNewDatabase = (mCurrentDb == null);
|
||||||
SQLiteDatabase db = mCurrentDb != null ? mCurrentDb : getWritableDatabase();
|
SQLiteDatabase db = mCurrentDb != null ? mCurrentDb : getWritableDatabase();
|
||||||
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
|
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
|
||||||
|
|
||||||
@ -384,6 +401,12 @@ public class Database extends SQLiteOpenHelper {
|
|||||||
rowId = db.insert(UserIds.TABLE_NAME, UserIds.USER_ID, values);
|
rowId = db.insert(UserIds.TABLE_NAME, UserIds.USER_ID, values);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
c.close();
|
||||||
|
|
||||||
|
if (grabbedNewDatabase) {
|
||||||
|
db.close();
|
||||||
|
}
|
||||||
|
|
||||||
return rowId;
|
return rowId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,4 +31,14 @@ public class KeyRings implements BaseColumns {
|
|||||||
public static final String WHO_ID_type = "INTEGER";
|
public static final String WHO_ID_type = "INTEGER";
|
||||||
public static final String KEY_RING_DATA = "c_key_ring_data";
|
public static final String KEY_RING_DATA = "c_key_ring_data";
|
||||||
public static final String KEY_RING_DATA_type = "BLOB";
|
public static final String KEY_RING_DATA_type = "BLOB";
|
||||||
|
|
||||||
|
public static final Uri CONTENT_URI =
|
||||||
|
Uri.parse("content://" + DataProvider.AUTHORITY + "/key_ring");
|
||||||
|
public static final Uri CONTENT_URI_BY_KEY_ID =
|
||||||
|
Uri.parse("content://" + DataProvider.AUTHORITY + "/key_ring/key_id");
|
||||||
|
public static final String CONTENT_TYPE =
|
||||||
|
"vnd.android.cursor.dir/vnd.thialfihar.apg.key_ring";
|
||||||
|
public static final String CONTENT_ITEM_TYPE =
|
||||||
|
"vnd.android.cursor.item/vnd.thialfihar.apg.key_ring";
|
||||||
|
public static final String DEFAULT_SORT_ORDER = _ID + " DESC";
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package org.thialfihar.android.apg.provider;
|
package org.thialfihar.android.apg.provider;
|
||||||
|
|
||||||
|
import android.net.Uri;
|
||||||
import android.provider.BaseColumns;
|
import android.provider.BaseColumns;
|
||||||
|
|
||||||
public class Keys implements BaseColumns {
|
public class Keys implements BaseColumns {
|
||||||
@ -42,4 +43,12 @@ public class Keys implements BaseColumns {
|
|||||||
public static final String KEY_DATA_type = "BLOB";
|
public static final String KEY_DATA_type = "BLOB";
|
||||||
public static final String RANK = "c_key_data";
|
public static final String RANK = "c_key_data";
|
||||||
public static final String RANK_type = "INTEGER";
|
public static final String RANK_type = "INTEGER";
|
||||||
|
|
||||||
|
public static final Uri CONTENT_URI =
|
||||||
|
Uri.parse("content://" + DataProvider.AUTHORITY + "/keys");
|
||||||
|
public static final String CONTENT_TYPE =
|
||||||
|
"vnd.android.cursor.dir/vnd.thialfihar.apg.key";
|
||||||
|
public static final String CONTENT_ITEM_TYPE =
|
||||||
|
"vnd.android.cursor.item/vnd.thialfihar.apg.key";
|
||||||
|
public static final String DEFAULT_SORT_ORDER = _ID + " DESC";
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package org.thialfihar.android.apg.provider;
|
package org.thialfihar.android.apg.provider;
|
||||||
|
|
||||||
|
import android.net.Uri;
|
||||||
import android.provider.BaseColumns;
|
import android.provider.BaseColumns;
|
||||||
|
|
||||||
public class UserIds implements BaseColumns {
|
public class UserIds implements BaseColumns {
|
||||||
@ -28,4 +29,14 @@ public class UserIds implements BaseColumns {
|
|||||||
public static final String USER_ID_type = "TEXT";
|
public static final String USER_ID_type = "TEXT";
|
||||||
public static final String RANK = "c_rank";
|
public static final String RANK = "c_rank";
|
||||||
public static final String RANK_type = "INTEGER";
|
public static final String RANK_type = "INTEGER";
|
||||||
|
|
||||||
|
public static final Uri CONTENT_URI =
|
||||||
|
Uri.parse("content://" + DataProvider.AUTHORITY + "/user_ids");
|
||||||
|
public static final Uri CONTENT_URI_BY_KEY_ID =
|
||||||
|
Uri.parse("content://" + DataProvider.AUTHORITY + "/user_ids/key_id");
|
||||||
|
public static final String CONTENT_TYPE =
|
||||||
|
"vnd.android.cursor.dir/vnd.thialfihar.apg.user_id";
|
||||||
|
public static final String CONTENT_ITEM_TYPE =
|
||||||
|
"vnd.android.cursor.item/vnd.thialfihar.apg.user_id";
|
||||||
|
public static final String DEFAULT_SORT_ORDER = _ID + " DESC";
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user