From 428e94bb57764729efa72887110194300e63b28e Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Thu, 3 Apr 2014 17:08:04 +0200 Subject: ditch useless PgpKeyHelper.getMasterKey methods --- .../keychain/pgp/PgpDecryptVerify.java | 8 +-- .../keychain/pgp/PgpKeyHelper.java | 28 --------- .../keychain/pgp/PgpSignEncrypt.java | 4 +- .../keychain/provider/ProviderHelper.java | 68 ++++------------------ .../keychain/service/PassphraseCacheService.java | 2 +- .../keychain/ui/EditKeyActivity.java | 9 ++- .../keychain/ui/EncryptAsymmetricFragment.java | 4 +- 7 files changed, 23 insertions(+), 100 deletions(-) (limited to 'OpenPGP-Keychain/src') diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java index 11b87fc97..77edd353c 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java @@ -241,7 +241,7 @@ public class PgpDecryptVerify { // TODO: improve this code! get master key directly! PGPSecretKeyRing secretKeyRing = ProviderHelper.getPGPSecretKeyRingWithKeyId(mContext, encData.getKeyID()); - long masterKeyId = PgpKeyHelper.getMasterKey(secretKeyRing).getKeyID(); + long masterKeyId = secretKeyRing.getSecretKey().getKeyID(); Log.d(Constants.TAG, "encData.getKeyID():" + encData.getKeyID()); Log.d(Constants.TAG, "allowedKeyIds: " + mAllowedKeyIds); Log.d(Constants.TAG, "masterKeyId: " + masterKeyId); @@ -375,7 +375,7 @@ public class PgpDecryptVerify { PGPPublicKeyRing signKeyRing = ProviderHelper.getPGPPublicKeyRingWithKeyId( mContext, signatureKeyId); if (signKeyRing != null) { - userId = PgpKeyHelper.getMainUserId(PgpKeyHelper.getMasterKey(signKeyRing)); + userId = PgpKeyHelper.getMainUserId(signKeyRing.getPublicKey()); } signatureResult.setUserId(userId); break; @@ -559,7 +559,7 @@ public class PgpDecryptVerify { PGPPublicKeyRing signKeyRing = ProviderHelper.getPGPPublicKeyRingWithKeyId(mContext, signatureKeyId); if (signKeyRing != null) { - userId = PgpKeyHelper.getMainUserId(PgpKeyHelper.getMasterKey(signKeyRing)); + userId = PgpKeyHelper.getMainUserId(signKeyRing.getPublicKey()); } signatureResult.setUserId(userId); break; @@ -624,7 +624,7 @@ public class PgpDecryptVerify { signatureKeyId); PGPPublicKey mKey = null; if (signKeyRing != null) { - mKey = PgpKeyHelper.getMasterKey(signKeyRing); + mKey = signKeyRing.getPublicKey(); } if (signature.getKeyID() != mKey.getKeyID()) { diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java index 290c8870b..9a97bc717 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyHelper.java @@ -60,34 +60,6 @@ public class PgpKeyHelper { return key.getPublicKey().getCreationTime(); } - @SuppressWarnings("unchecked") - public static PGPPublicKey getMasterKey(PGPPublicKeyRing keyRing) { - if (keyRing == null) { - return null; - } - for (PGPPublicKey key : new IterableIterator(keyRing.getPublicKeys())) { - if (key.isMasterKey()) { - return key; - } - } - - return null; - } - - @SuppressWarnings("unchecked") - public static PGPSecretKey getMasterKey(PGPSecretKeyRing keyRing) { - if (keyRing == null) { - return null; - } - for (PGPSecretKey key : new IterableIterator(keyRing.getSecretKeys())) { - if (key.isMasterKey()) { - return key; - } - } - - return null; - } - @SuppressWarnings("unchecked") public static PGPSecretKey getKeyNum(PGPSecretKeyRing keyRing, long num) { long cnt = 0; diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java index c1baed402..a864a165d 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java @@ -306,7 +306,7 @@ public class PgpSignEncrypt { signatureGenerator = new PGPSignatureGenerator(contentSignerBuilder); signatureGenerator.init(signatureType, signaturePrivateKey); - String userId = PgpKeyHelper.getMainUserId(PgpKeyHelper.getMasterKey(signingKeyRing)); + String userId = PgpKeyHelper.getMainUserId(signingKeyRing.getSecretKey()); PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator(); spGen.setSignerUserID(false, userId); signatureGenerator.setHashedSubpackets(spGen.generate()); @@ -505,7 +505,7 @@ public class PgpSignEncrypt { signatureGenerator.init(type, signaturePrivateKey); PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator(); - String userId = PgpKeyHelper.getMainUserId(PgpKeyHelper.getMasterKey(signingKeyRing)); + String userId = PgpKeyHelper.getMainUserId(signingKeyRing.getSecretKey()); spGen.setSignerUserID(false, userId); signatureGenerator.setHashedSubpackets(spGen.generate()); } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java index 3f96a51ef..3a0d910c5 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java @@ -260,30 +260,6 @@ public class ProviderHelper { return ContentProviderOperation.newInsert(uri).withValues(values).build(); } - /** - * Private helper method - */ - private static ArrayList getKeyRingsMasterKeyIds(Context context, Uri queryUri) { - Cursor cursor = context.getContentResolver().query(queryUri, - new String[]{KeyRings.MASTER_KEY_ID}, null, null, null); - - ArrayList masterKeyIds = new ArrayList(); - if (cursor != null) { - int masterKeyIdCol = cursor.getColumnIndex(KeyRings.MASTER_KEY_ID); - if (cursor.moveToFirst()) { - do { - masterKeyIds.add(cursor.getLong(masterKeyIdCol)); - } while (cursor.moveToNext()); - } - } - - if (cursor != null) { - cursor.close(); - } - - return masterKeyIds; - } - public static void deletePublicKeyRing(Context context, long masterKeyId) { ContentResolver cr = context.getContentResolver(); cr.delete(KeyRings.buildPublicKeyRingUri(Long.toString(masterKeyId)), null, null); @@ -294,38 +270,6 @@ public class ProviderHelper { cr.delete(KeyRings.buildSecretKeyRingUri(Long.toString(masterKeyId)), null, null); } - public static boolean getMasterKeyCanCertify(Context context, Uri queryUri) { - // TODO redo - - return false; - - /* - String[] projection = new String[]{ - KeyRings.MASTER_KEY_ID, - "(SELECT COUNT(sign_keys." + Keys._ID + ") FROM " + Tables.KEYS - + " AS sign_keys WHERE sign_keys." + Keys.KEY_RING_ROW_ID + " = " - + KeychainDatabase.Tables.KEY_RINGS + "." + KeyRings._ID - + " AND sign_keys." + Keys.CAN_CERTIFY + " = '1' AND " + Keys.IS_MASTER_KEY - + " = 1) AS sign",}; - - ContentResolver cr = context.getContentResolver(); - Cursor cursor = cr.query(queryUri, projection, null, null, null); - - long masterKeyId = -1; - if (cursor != null && cursor.moveToFirst()) { - int masterKeyIdCol = cursor.getColumnIndex("sign"); - - masterKeyId = cursor.getLong(masterKeyIdCol); - } - - if (cursor != null) { - cursor.close(); - } - - return (masterKeyId > 0); - */ - } - public static boolean hasSecretKeyByMasterKeyId(Context context, long masterKeyId) { Uri queryUri = KeyRings.buildSecretKeyRingUri(Long.toString(masterKeyId)); // see if we can get our master key id back from the uri @@ -336,8 +280,16 @@ public class ProviderHelper { * Get master key id of key */ public static long getMasterKeyId(Context context, Uri queryUri) { - String[] projection = new String[]{KeyRings.MASTER_KEY_ID}; - Cursor cursor = context.getContentResolver().query(queryUri, projection, null, null, null); + // try extracting from the uri first + try { + return Long.parseLong(queryUri.getPathSegments().get(1)); + } catch(NumberFormatException e) { + // didn't work? oh well. + } + + Cursor cursor = context.getContentResolver().query(queryUri, new String[] { + KeyRings.MASTER_KEY_ID + }, null, null, null); long masterKeyId = 0; try { diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java index 63703a02b..0ec4c1239 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java @@ -174,7 +174,7 @@ public class PassphraseCacheService extends Service { if (keyRing == null) { return null; } - PGPSecretKey masterKey = PgpKeyHelper.getMasterKey(keyRing); + PGPSecretKey masterKey = keyRing.getSecretKey(); if (masterKey == null) { return null; } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java index d7ff8c207..0caf60aa1 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java @@ -276,8 +276,6 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener // get master key id using row id long masterKeyId = ProviderHelper.getMasterKeyId(this, mDataUri); - - mMasterCanSign = ProviderHelper.getMasterKeyCanCertify(this, mDataUri); finallyEdit(masterKeyId); } } @@ -347,8 +345,7 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener } return true; case R.id.menu_key_edit_delete: - long rowId= ProviderHelper.getRowId(this,mDataUri); - Uri convertUri = KeychainContract.KeyRings.buildSecretKeyRingUri(Long.toString(rowId)); + Uri convertUri = KeychainContract.KeyRings.buildSecretKeyRingUri(mDataUri); // Message is received after key is deleted Handler returnHandler = new Handler() { @Override @@ -374,7 +371,8 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener PGPSecretKey masterKey = null; mKeyRing = ProviderHelper.getPGPSecretKeyRing(this, masterKeyId); if (mKeyRing != null) { - masterKey = PgpKeyHelper.getMasterKey(mKeyRing); + masterKey = mKeyRing.getSecretKey(); + mMasterCanSign = PgpKeyHelper.isCertificationKey(mKeyRing.getSecretKey()); for (PGPSecretKey key : new IterableIterator(mKeyRing.getSecretKeys())) { mKeys.add(key); mKeysUsages.add(-1); // get usage when view is created @@ -382,6 +380,7 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener } else { Log.e(Constants.TAG, "Keyring not found with masterKeyId: " + masterKeyId); Toast.makeText(this, R.string.error_no_secret_key_found, Toast.LENGTH_LONG).show(); + // TODO } if (masterKey != null) { boolean isSet = false; diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java index 6b0e1d9f1..a8de40c70 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java @@ -145,7 +145,7 @@ public class EncryptAsymmetricFragment extends Fragment { preselectedSignatureKeyId); PGPSecretKey masterKey; if (keyRing != null) { - masterKey = PgpKeyHelper.getMasterKey(keyRing); + masterKey = keyRing.getSecretKey(); if (masterKey != null) { Vector signKeys = PgpKeyHelper.getUsableSigningKeys(keyRing); if (signKeys.size() > 0) { @@ -166,7 +166,7 @@ public class EncryptAsymmetricFragment extends Fragment { if (keyRing == null) { continue; } - masterKey = PgpKeyHelper.getMasterKey(keyRing); + masterKey = keyRing.getPublicKey(); if (masterKey == null) { continue; } -- cgit v1.2.3 From dedcfd8a7243a8ff5740ad706bc749d57ee8b5e8 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Thu, 3 Apr 2014 17:09:26 +0200 Subject: more work on streamlining uris, and stripping ProviderHelper --- .../keychain/provider/KeychainProvider.java | 5 + .../keychain/provider/ProviderHelper.java | 134 +++++++++------------ .../remote/ui/AccountSettingsFragment.java | 6 +- .../keychain/ui/EncryptAsymmetricFragment.java | 23 ++-- .../keychain/ui/KeyListFragment.java | 27 ++--- .../keychain/ui/ViewKeyActivity.java | 13 +- .../keychain/ui/ViewKeyActivityJB.java | 19 ++- .../keychain/ui/ViewKeyMainFragment.java | 4 - .../ui/dialog/DeleteKeyDialogFragment.java | 125 ++++++------------- .../ui/dialog/ShareQrCodeDialogFragment.java | 15 ++- 10 files changed, 148 insertions(+), 223 deletions(-) (limited to 'OpenPGP-Keychain/src') diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java index 39ea083fa..a4fd1130d 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java @@ -256,6 +256,9 @@ public class KeychainProvider extends ContentProvider { + Tables.USER_IDS + "." + UserIdsColumns.USER_ID + " ASC"; } + // uri to watch is all /key_rings/ + uri = KeyRings.CONTENT_URI; + break; } /*case SECRET_KEY_RING_BY_EMAILS: @@ -503,6 +506,7 @@ public class KeychainProvider extends ContentProvider { } // corresponding keys and userIds are deleted by ON DELETE CASCADE count = db.delete(Tables.KEY_RINGS_PUBLIC, selection, selectionArgs); + uri = KeyRings.buildGenericKeyRingUri(uri.getPathSegments().get(1)); break; } case KEY_RING_SECRET: { @@ -512,6 +516,7 @@ public class KeychainProvider extends ContentProvider { selection += " AND (" + additionalSelection + ")"; } count = db.delete(Tables.KEY_RINGS_SECRET, selection, selectionArgs); + uri = KeyRings.buildGenericKeyRingUri(uri.getPathSegments().get(1)); break; } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java index 3a0d910c5..18eaa375a 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java @@ -23,7 +23,10 @@ import android.content.ContentValues; import android.content.Context; import android.content.OperationApplicationException; import android.database.Cursor; +import android.database.CursorWindow; +import android.database.CursorWrapper; import android.database.DatabaseUtils; +import android.database.sqlite.SQLiteCursor; import android.net.Uri; import android.os.RemoteException; @@ -42,7 +45,6 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.ApiApps; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.KeychainContract.Keys; import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds; -import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables; import org.sufficientlysecure.keychain.remote.AccountSettings; import org.sufficientlysecure.keychain.remote.AppSettings; import org.sufficientlysecure.keychain.util.IterableIterator; @@ -52,6 +54,7 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.Date; +import java.util.HashMap; import java.util.HashSet; import java.util.Set; @@ -81,6 +84,57 @@ public class ProviderHelper { return keyRing; } + public static Object getUnifiedData(Context context, long masterKeyId, String column) { + return getUnifiedData(context, masterKeyId, new String[] { column }).get(column); + } + public static Object getUnifiedData(Context context, Uri uri, String column) { + return getUnifiedData(context, uri, new String[] { column }).get(column); + } + + public static HashMap getUnifiedData(Context context, long masterKeyId, String[] proj) { + return getUnifiedData(context, KeyRings.buildGenericKeyRingUri(Long.toString(masterKeyId)), proj); + } + + public static HashMap getUnifiedData(Context context, Uri uri, String[] proj) { + uri = KeyRings.buildUnifiedKeyRingUri(uri); + + Cursor cursor = context.getContentResolver().query(uri, proj, null, null, null); + + HashMap result = new HashMap(proj.length); + if (cursor != null && cursor.moveToFirst()) { + // this is a HACK because we don't have Cursor.getType (which is api level 11) + CursorWindow cursorWindow; + if(cursor instanceof CursorWrapper) { + cursorWindow = ((SQLiteCursor) ((CursorWrapper) cursor).getWrappedCursor()).getWindow(); + } else { + cursorWindow = ((SQLiteCursor) cursor).getWindow(); + } + + int pos = 0; + for(String p : proj) { + if (cursorWindow.isNull(0, pos)) { + result.put(p, cursor.isNull(pos)); + } else if (cursorWindow.isLong(0, pos)) { + result.put(p, cursor.getLong(pos)); + } else if (cursorWindow.isFloat(0, pos)) { + result.put(p, cursor.getFloat(pos)); + } else if (cursorWindow.isString(0, pos)) { + result.put(p, cursor.getString(pos)); + } else if (cursorWindow.isBlob(0, pos)) { + result.put(p, cursor.getBlob(pos)); + } + pos += 1; + } + } + + if (cursor != null) { + cursor.close(); + } + + return result; + } + + public static PGPPublicKey getPGPPublicKeyByKeyId(Context context, long keyId) { return getPGPPublicKeyRingWithKeyId(context, keyId).getPublicKey(keyId); } @@ -307,84 +361,6 @@ public class ProviderHelper { return masterKeyId; } - public static long getRowId(Context context, Uri queryUri) { - String[] projection = new String[]{KeyRings._ID}; - Cursor cursor = context.getContentResolver().query(queryUri, projection, null, null, null); - - long rowId = 0; - try { - if (cursor != null && cursor.moveToFirst()) { - int idCol = cursor.getColumnIndexOrThrow(KeyRings._ID); - - rowId = cursor.getLong(idCol); - } - } finally { - if (cursor != null) { - cursor.close(); - } - } - - return rowId; - } - - /** - * Get fingerprint of key - */ - public static byte[] getFingerprint(Context context, Uri queryUri) { - String[] projection = new String[]{Keys.FINGERPRINT}; - Cursor cursor = context.getContentResolver().query(queryUri, projection, null, null, null); - - byte[] fingerprint = null; - try { - if (cursor != null && cursor.moveToFirst()) { - int col = cursor.getColumnIndexOrThrow(Keys.FINGERPRINT); - - fingerprint = cursor.getBlob(col); - } - } finally { - if (cursor != null) { - cursor.close(); - } - } - - // FALLBACK: If fingerprint is not in database, get it from key blob! - // this could happen if the key was saved by a previous version of Keychain! - if (fingerprint == null) { - Log.d(Constants.TAG, "FALLBACK: fingerprint is not in database, get it from key blob!"); - - // get master key id - projection = new String[]{KeyRings.MASTER_KEY_ID}; - cursor = context.getContentResolver().query(queryUri, projection, null, null, null); - long masterKeyId = 0; - try { - if (cursor != null && cursor.moveToFirst()) { - int col = cursor.getColumnIndexOrThrow(KeyRings.MASTER_KEY_ID); - - masterKeyId = cursor.getLong(col); - } - } finally { - if (cursor != null) { - cursor.close(); - } - } - - PGPPublicKey key = ProviderHelper.getPGPPublicKeyRing(context, masterKeyId).getPublicKey(); - // if it is no public key get it from your own keys... - if (key == null) { - PGPSecretKey secretKey = ProviderHelper.getPGPSecretKeyRing(context, masterKeyId).getSecretKey(); - if (secretKey == null) { - Log.e(Constants.TAG, "Key could not be found!"); - return null; - } - key = secretKey.getPublicKey(); - } - - fingerprint = key.getFingerprint(); - } - - return fingerprint; - } - public static ArrayList getKeyRingsAsArmoredString(Context context, Uri uri, long[] masterKeyIds) { ArrayList output = new ArrayList(); diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsFragment.java index dee0dae95..992aa7c95 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsFragment.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsFragment.java @@ -34,6 +34,7 @@ import com.beardedhen.androidbootstrap.BootstrapButton; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.provider.KeychainContract; +import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.remote.AccountSettings; import org.sufficientlysecure.keychain.ui.EditKeyActivity; import org.sufficientlysecure.keychain.ui.SelectSecretKeyLayoutFragment; @@ -176,9 +177,8 @@ public class AccountSettingsFragment extends Fragment implements case REQUEST_CODE_CREATE_KEY: { if (resultCode == Activity.RESULT_OK) { // select newly created key - Uri newKeyUri = data.getData(); - // TODO helper method for this? - mSelectKeyFragment.selectKey(Long.parseLong(newKeyUri.getPathSegments().get(1))); + long masterKeyId = ProviderHelper.getMasterKeyId(getActivity(), data.getData()); + mSelectKeyFragment.selectKey(masterKeyId); } break; } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java index a8de40c70..0b724d52c 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java @@ -37,8 +37,10 @@ import org.spongycastle.openpgp.PGPSecretKeyRing; import org.sufficientlysecure.keychain.Id; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; +import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.ProviderHelper; +import java.util.HashMap; import java.util.Vector; public class EncryptAsymmetricFragment extends Fragment { @@ -202,20 +204,17 @@ public class EncryptAsymmetricFragment extends Fragment { } else { String uid = getResources().getString(R.string.user_id_no_name); String uidExtra = ""; - // TODO: don't use bouncy castle objects! - PGPSecretKeyRing keyRing = ProviderHelper.getPGPSecretKeyRingWithKeyId(getActivity(), - mSecretKeyId); - if (keyRing != null) { - PGPSecretKey key = PgpKeyHelper.getMasterKey(keyRing); - if (key != null) { - String userId = PgpKeyHelper.getMainUserIdSafe(getActivity(), key); - String chunks[] = userId.split(" <", 2); - uid = chunks[0]; - if (chunks.length > 1) { - uidExtra = "<" + chunks[1]; - } + // See if we can get a user_id from a unified query + Object data = ProviderHelper.getUnifiedData( + getActivity(), mSecretKeyId, KeychainContract.UserIds.USER_ID); + if(data instanceof String) { + String chunks[] = ((String) data).split(" <", 2); + uid = chunks[0]; + if (chunks.length > 1) { + uidExtra = "<" + chunks[1]; } } + mMainUserId.setText(uid); mMainUserIdRest.setText(uidExtra); mSign.setChecked(true); diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java index 6dec5e56e..cc0abe48a 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java @@ -193,28 +193,15 @@ public class KeyListFragment extends Fragment break; } case R.id.menu_key_list_multi_delete: { - ids = mStickyList.getWrappedList().getCheckedItemIds(); + ids = mAdapter.getCurrentSelectedMasterKeyIds(); showDeleteKeyDialog(mode, ids); break; } case R.id.menu_key_list_multi_export: { - ids = mStickyList.getWrappedList().getCheckedItemIds(); - long[] masterKeyIds = new long[2*ids.length]; - /* TODO! redo - ArrayList allPubRowIds = - ProviderHelper.getPublicKeyRingsRowIds(getActivity()); - for (int i = 0; i < ids.length; i++) { - if (allPubRowIds.contains(ids[i])) { - masterKeyIds[i] = - ProviderHelper.getPublicMasterKeyId(getActivity(), ids[i]); - } else { - masterKeyIds[i] = - ProviderHelper.getSecretMasterKeyId(getActivity(), ids[i]); - } - }*/ + ids = mAdapter.getCurrentSelectedMasterKeyIds(); ExportHelper mExportHelper = new ExportHelper((ActionBarActivity) getActivity()); mExportHelper - .showExportKeysDialog(masterKeyIds, Id.type.public_key, + .showExportKeysDialog(ids, Id.type.public_key, Constants.Path.APP_DIR_FILE_PUB, getString(R.string.also_export_secret_keys)); break; @@ -343,7 +330,7 @@ public class KeyListFragment extends Fragment } viewIntent.setData( KeychainContract - .KeyRings.buildPublicKeyRingUri( + .KeyRings.buildGenericKeyRingUri( Long.toString(mAdapter.getMasterKeyId(position)))); startActivity(viewIntent); } @@ -362,11 +349,11 @@ public class KeyListFragment extends Fragment /** * Show dialog to delete key * - * @param keyRingRowIds + * @param masterKeyIds */ @TargetApi(11) // TODO: this method needs an overhaul to handle both public and secret keys gracefully! - public void showDeleteKeyDialog(final ActionMode mode, long[] keyRingRowIds) { + public void showDeleteKeyDialog(final ActionMode mode, long[] masterKeyIds) { // Message is received after key is deleted Handler returnHandler = new Handler() { @Override @@ -381,7 +368,7 @@ public class KeyListFragment extends Fragment Messenger messenger = new Messenger(returnHandler); DeleteKeyDialogFragment deleteKeyDialog = DeleteKeyDialogFragment.newInstance(messenger, - keyRingRowIds); + masterKeyIds); deleteKeyDialog.show(getActivity().getSupportFragmentManager(), "deleteKeyDialog"); } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java index 54fd04b10..2437270e5 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java @@ -173,10 +173,15 @@ public class ViewKeyActivity extends ActionBarActivity { private void shareKey(Uri dataUri, boolean fingerprintOnly) { String content; if (fingerprintOnly) { - byte[] fingerprintBlob = ProviderHelper.getFingerprint(this, dataUri); - String fingerprint = PgpKeyHelper.convertFingerprintToHex(fingerprintBlob); - - content = Constants.FINGERPRINT_SCHEME + ":" + fingerprint; + Object blob = ProviderHelper.getUnifiedData(this, dataUri, KeychainContract.Keys.FINGERPRINT); + if(blob instanceof byte[]) { + String fingerprint = PgpKeyHelper.convertFingerprintToHex((byte[]) blob); + content = Constants.FINGERPRINT_SCHEME + ":" + fingerprint; + } else { + Toast.makeText(getApplicationContext(), "Bad key selected!", + Toast.LENGTH_LONG).show(); + return; + } } else { // get public keyring as ascii armored string long masterKeyId = ProviderHelper.getMasterKeyId(this, dataUri); diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivityJB.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivityJB.java index 997ff9c7a..9bbbb6c7b 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivityJB.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivityJB.java @@ -34,6 +34,9 @@ import android.widget.Toast; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.provider.ProviderHelper; +import org.sufficientlysecure.keychain.util.Log; + +import java.io.IOException; @TargetApi(Build.VERSION_CODES.JELLY_BEAN) public class ViewKeyActivityJB extends ViewKeyActivity implements CreateNdefMessageCallback, @@ -64,13 +67,17 @@ public class ViewKeyActivityJB extends ViewKeyActivity implements CreateNdefMess // get public keyring as byte array long masterKeyId = ProviderHelper.getMasterKeyId(this, dataUri); - mSharedKeyringBytes = ProviderHelper.getKeyRingsAsByteArray(this, dataUri, - new long[]{masterKeyId}); + try { + mSharedKeyringBytes = ProviderHelper.getPGPPublicKeyRing(this, masterKeyId).getEncoded(); - // Register callback to set NDEF message - mNfcAdapter.setNdefPushMessageCallback(this, this); - // Register callback to listen for message-sent success - mNfcAdapter.setOnNdefPushCompleteCallback(this, this); + // Register callback to set NDEF message + mNfcAdapter.setNdefPushMessageCallback(this, this); + // Register callback to listen for message-sent success + mNfcAdapter.setOnNdefPushCompleteCallback(this, this); + } catch(IOException e) { + // not much trouble, but leave a note + Log.e(Constants.TAG, "Error parsing keyring: ", e); + } } } } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java index 703f7e861..75853ac2a 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java @@ -298,10 +298,6 @@ public class ViewKeyMainFragment extends Fragment implements mAlgorithm.setText(algorithmStr); byte[] fingerprintBlob = data.getBlob(KEYS_INDEX_FINGERPRINT); - if (fingerprintBlob == null) { - // FALLBACK for old database entries - fingerprintBlob = ProviderHelper.getFingerprint(getActivity(), mDataUri); - } String fingerprint = PgpKeyHelper.convertFingerprintToHex(fingerprintBlob); mFingerprint.setText(PgpKeyHelper.colorizeFingerprint(fingerprint)); diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java index 9427ce0db..57dbb7794 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java @@ -43,10 +43,11 @@ import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.util.Log; import java.util.ArrayList; +import java.util.HashMap; public class DeleteKeyDialogFragment extends DialogFragment { private static final String ARG_MESSENGER = "messenger"; - private static final String ARG_DELETE_KEY_RING_ROW_IDS = "delete_key_ring_row_ids"; + private static final String ARG_DELETE_MASTER_KEY_IDS = "delete_master_key_ids"; public static final int MESSAGE_OKAY = 1; public static final int MESSAGE_ERROR = 0; @@ -63,13 +64,13 @@ public class DeleteKeyDialogFragment extends DialogFragment { /** * Creates new instance of this delete file dialog fragment */ - public static DeleteKeyDialogFragment newInstance(Messenger messenger, long[] keyRingRowIds - ) { + public static DeleteKeyDialogFragment newInstance(Messenger messenger, + long[] masterKeyIds) { DeleteKeyDialogFragment frag = new DeleteKeyDialogFragment(); Bundle args = new Bundle(); args.putParcelable(ARG_MESSENGER, messenger); - args.putLongArray(ARG_DELETE_KEY_RING_ROW_IDS, keyRingRowIds); + args.putLongArray(ARG_DELETE_MASTER_KEY_IDS, masterKeyIds); //We don't need the key type frag.setArguments(args); @@ -84,7 +85,7 @@ public class DeleteKeyDialogFragment extends DialogFragment { final FragmentActivity activity = getActivity(); mMessenger = getArguments().getParcelable(ARG_MESSENGER); - final long[] keyRingRowIds = getArguments().getLongArray(ARG_DELETE_KEY_RING_ROW_IDS); + final long[] masterKeyIds = getArguments().getLongArray(ARG_DELETE_MASTER_KEY_IDS); AlertDialog.Builder builder = new AlertDialog.Builder(activity); @@ -98,35 +99,29 @@ public class DeleteKeyDialogFragment extends DialogFragment { mCheckDeleteSecret = (CheckBox) mInflateView.findViewById(R.id.checkDeleteSecret); builder.setTitle(R.string.warning); - /* TODO! redo - //If only a single key has been selected - if (keyRingRowIds.length == 1) { - Uri dataUri; - ArrayList publicKeyRings; //Any one will do + // If only a single key has been selected + if (masterKeyIds.length == 1) { mIsSingleSelection = true; - long selectedRow = keyRingRowIds[0]; - long keyType; - publicKeyRings = ProviderHelper.getPublicKeyRingsRowIds(activity); - - if (publicKeyRings.contains(selectedRow)) { - //TODO Should be a better method to do this other than getting all the KeyRings - dataUri = KeychainContract.KeyRings.buildPublicKeyRingsUri(String.valueOf(selectedRow)); - keyType = Id.type.public_key; - } else { - dataUri = KeychainContract.KeyRings.buildSecretKeyRingsUri(String.valueOf(selectedRow)); - keyType = Id.type.secret_key; - } + long masterKeyId = masterKeyIds[0]; + + HashMap data = ProviderHelper.getUnifiedData(activity, masterKeyId, new String[]{ + KeychainContract.UserIds.USER_ID, + KeychainDatabase.Tables.KEY_RINGS_SECRET + "." + KeychainContract.KeyRings.MASTER_KEY_ID + }); + String userId = (String) data.get(KeychainContract.UserIds.USER_ID); + boolean hasSecret = data.get( + KeychainDatabase.Tables.KEY_RINGS_SECRET + "." + KeychainContract.KeyRings.MASTER_KEY_ID + ) instanceof Long; - String userId = ProviderHelper.getUserId(activity, dataUri); - // Hide the Checkbox and TextView since this is a single selection, - // user will be notified thru message + // Hide the Checkbox and TextView since this is a single selection,user will be notified through message mDeleteSecretKeyView.setVisibility(View.GONE); // Set message depending on which key it is. - mMainMessage.setText(getString(keyType == Id.type.secret_key ? - R.string.secret_key_deletion_confirmation : - R.string.public_key_deletetion_confirmation, userId)); + mMainMessage.setText(getString( + hasSecret ? R.string.secret_key_deletion_confirmation + : R.string.public_key_deletetion_confirmation, + userId)); } else { mDeleteSecretKeyView.setVisibility(View.VISIBLE); mMainMessage.setText(R.string.key_deletion_confirmation_multi); @@ -137,75 +132,27 @@ public class DeleteKeyDialogFragment extends DialogFragment { builder.setPositiveButton(R.string.btn_delete, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - Uri queryUri = KeychainContract.KeyRings.buildUnifiedKeyRingsUri(); - String[] projection = new String[]{ - KeychainContract.KeyRings.MASTER_KEY_ID, // 0 - KeychainContract.KeyRings.TYPE// 1 - }; - - // make selection with all entries where _ID is one of the given row ids - String selection = KeychainDatabase.Tables.KEY_RINGS + "." + - KeychainContract.KeyRings._ID + " IN("; - String selectionIDs = ""; - for (int i = 0; i < keyRingRowIds.length; i++) { - selectionIDs += "'" + String.valueOf(keyRingRowIds[i]) + "'"; - if (i + 1 < keyRingRowIds.length) { - selectionIDs += ","; - } - } - selection += selectionIDs + ")"; - - Cursor cursor = activity.getContentResolver().query(queryUri, projection, - selection, null, null); - - - long masterKeyId; - long keyType; - boolean isSuccessfullyDeleted; - try { - isSuccessfullyDeleted = false; - while (cursor != null && cursor.moveToNext()) { - masterKeyId = cursor.getLong(0); - keyType = cursor.getLong(1); - - Log.d(Constants.TAG, "masterKeyId: " + masterKeyId + - ", keyType:" + - (keyType == KeychainContract.KeyTypes.PUBLIC ? - "Public" : "Private")); - - if (keyType == KeychainContract.KeyTypes.SECRET) { - if (mCheckDeleteSecret.isChecked() || mIsSingleSelection) { - ProviderHelper.deleteUnifiedKeyRing(activity, - String.valueOf(masterKeyId), true); - } - } else { - ProviderHelper.deleteUnifiedKeyRing(activity, - String.valueOf(masterKeyId), false); - } - } - - //Check if the selected rows have actually been deleted - cursor = activity.getContentResolver().query( - queryUri, projection, selection, null, null); - if (cursor == null || cursor.getCount() == 0 || - !mCheckDeleteSecret.isChecked()) { - isSuccessfullyDeleted = true; - } - } finally { - if (cursor != null) { - cursor.close(); - } + + boolean success = false; + for(long masterKeyId : masterKeyIds) { + int count = activity.getContentResolver().delete( + KeychainContract.KeyRings.buildPublicKeyRingUri(Long.toString(masterKeyId)), null, null + ); + if(count > 0) + success = true; } dismiss(); - if (isSuccessfullyDeleted) { + if (success) { sendMessageToHandler(MESSAGE_OKAY, null); } else { sendMessageToHandler(MESSAGE_ERROR, null); } } - }); + + } + ); builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { @Override @@ -213,7 +160,7 @@ public class DeleteKeyDialogFragment extends DialogFragment { dismiss(); } }); - */ + return builder.create(); } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareQrCodeDialogFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareQrCodeDialogFragment.java index 18403837a..1b81c8b3b 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareQrCodeDialogFragment.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareQrCodeDialogFragment.java @@ -31,6 +31,7 @@ import android.widget.TextView; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; +import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.util.QrCodeUtils; @@ -89,22 +90,24 @@ public class ShareQrCodeDialogFragment extends DialogFragment { if (mFingerprintOnly) { alert.setPositiveButton(R.string.btn_okay, null); - byte[] fingerprintBlob = ProviderHelper.getFingerprint(getActivity(), dataUri); - String fingerprint = PgpKeyHelper.convertFingerprintToHex(fingerprintBlob); + Object blob = ProviderHelper.getUnifiedData(getActivity(), dataUri, KeychainContract.Keys.FINGERPRINT); + if(!(blob instanceof byte[])) { + // TODO error handling?! + return null; + } + String fingerprint = PgpKeyHelper.convertFingerprintToHex((byte[]) blob); mText.setText(getString(R.string.share_qr_code_dialog_fingerprint_text) + " " + fingerprint); - content = Constants.FINGERPRINT_SCHEME + ":" + fingerprint; setQrCode(content); } else { mText.setText(R.string.share_qr_code_dialog_start); - // TODO + // TODO works, but long masterKeyId = ProviderHelper.getMasterKeyId(getActivity(), dataUri); - // get public keyring as ascii armored string ArrayList keyringArmored = ProviderHelper.getKeyRingsAsArmoredString( - getActivity(), dataUri, new long[]{masterKeyId}); + getActivity(), dataUri, new long[] { masterKeyId }); // TODO: binary? -- cgit v1.2.3 From 2620e0bfc8cbbdfb304629dbcf8d3a9d2d0b35ae Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Thu, 3 Apr 2014 22:49:08 +0200 Subject: db-overhaul: more work on new provider specifics: - secret keys are preserved when a new public key is inserted - started work to give virtual columns a representation in the contract class - streamline ProviderHelper methods. the getUnifiedData method relies on a api level 11 method, not sure yet how to fix/workaround that... - many more small things work as they did before --- .../keychain/provider/KeychainContract.java | 36 +++-- .../keychain/provider/KeychainProvider.java | 139 +++++++++--------- .../keychain/provider/ProviderHelper.java | 159 +++++++-------------- .../keychain/service/KeychainIntentService.java | 4 +- .../keychain/ui/EditKeyActivity.java | 3 +- .../keychain/ui/KeyListFragment.java | 42 +++--- .../keychain/ui/ViewKeyActivity.java | 8 +- .../keychain/ui/ViewKeyMainFragment.java | 59 ++++---- .../ui/dialog/DeleteKeyDialogFragment.java | 19 +-- .../ui/dialog/ShareQrCodeDialogFragment.java | 2 +- 10 files changed, 208 insertions(+), 263 deletions(-) (limited to 'OpenPGP-Keychain/src') diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java index fcf8f7962..e6e106ba6 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java @@ -96,18 +96,14 @@ public class KeychainContract { public static final String BASE_API_APPS = "api_apps"; public static final String PATH_ACCOUNTS = "accounts"; - public static class KeyRings implements KeyRingsColumns, BaseColumns { + public static class KeyRings implements BaseColumns, KeysColumns, UserIdsColumns { + public static final String MASTER_KEY_ID = "master_key_id"; + public static final String HAS_SECRET = "has_secret"; + public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon() .appendPath(BASE_KEY_RINGS).build(); - /** - * Use if multiple items get returned - */ public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.sufficientlysecure.openkeychain.key_ring"; - - /** - * Use if a single item is returned - */ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.sufficientlysecure.openkeychain.key_ring"; public static Uri buildUnifiedKeyRingsUri() { @@ -121,6 +117,24 @@ public class KeychainContract { return CONTENT_URI.buildUpon().appendPath(masterKeyId).build(); } + public static Uri buildUnifiedKeyRingUri(String masterKeyId) { + return CONTENT_URI.buildUpon().appendPath(masterKeyId).appendPath(PATH_UNIFIED).build(); + } + public static Uri buildUnifiedKeyRingUri(Uri uri) { + return CONTENT_URI.buildUpon().appendPath(uri.getPathSegments().get(1)).appendPath(PATH_UNIFIED).build(); + } + } + + public static class KeyRingData implements KeyRingsColumns, BaseColumns { + public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon() + .appendPath(BASE_KEY_RINGS).build(); + + public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.sufficientlysecure.openkeychain.key_ring_data"; + public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.sufficientlysecure.openkeychain.key_ring_data"; + + public static Uri buildPublicKeyRingUri() { + return CONTENT_URI.buildUpon().appendPath(PATH_PUBLIC).build(); + } public static Uri buildPublicKeyRingUri(String masterKeyId) { return CONTENT_URI.buildUpon().appendPath(masterKeyId).appendPath(PATH_PUBLIC).build(); } @@ -135,12 +149,6 @@ public class KeychainContract { return CONTENT_URI.buildUpon().appendPath(uri.getPathSegments().get(1)).appendPath(PATH_SECRET).build(); } - public static Uri buildUnifiedKeyRingUri(String masterKeyId) { - return CONTENT_URI.buildUpon().appendPath(masterKeyId).appendPath(PATH_UNIFIED).build(); - } - public static Uri buildUnifiedKeyRingUri(Uri uri) { - return CONTENT_URI.buildUpon().appendPath(uri.getPathSegments().get(1)).appendPath(PATH_UNIFIED).build(); - } } public static class Keys implements KeysColumns, BaseColumns { diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java index a4fd1130d..8b1ee4886 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java @@ -26,19 +26,15 @@ import android.database.sqlite.SQLiteConstraintException; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteQueryBuilder; import android.net.Uri; -import android.provider.BaseColumns; import android.text.TextUtils; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.provider.KeychainContract.ApiAccounts; import org.sufficientlysecure.keychain.provider.KeychainContract.ApiApps; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; -import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingsColumns; -import org.sufficientlysecure.keychain.provider.KeychainContract.KeyTypes; +import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData; import org.sufficientlysecure.keychain.provider.KeychainContract.Keys; -import org.sufficientlysecure.keychain.provider.KeychainContract.KeysColumns; import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds; -import org.sufficientlysecure.keychain.provider.KeychainContract.UserIdsColumns; import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables; import org.sufficientlysecure.keychain.util.Log; @@ -46,13 +42,9 @@ import java.util.Arrays; import java.util.HashMap; public class KeychainProvider extends ContentProvider { - // public static final String ACTION_BROADCAST_DATABASE_CHANGE = Constants.PACKAGE_NAME - // + ".action.DATABASE_CHANGE"; - // - // public static final String EXTRA_BROADCAST_KEY_TYPE = "key_type"; - // public static final String EXTRA_BROADCAST_CONTENT_ITEM_TYPE = "contentItemType"; private static final int KEY_RINGS_UNIFIED = 101; + private static final int KEY_RINGS_PUBLIC = 102; private static final int KEY_RING_UNIFIED = 200; private static final int KEY_RING_KEYS = 201; @@ -79,18 +71,22 @@ public class KeychainProvider extends ContentProvider { String authority = KeychainContract.CONTENT_AUTHORITY; /** - * select from key_ring + * list key_rings * *
          * key_rings/unified
+         * key_rings/public
          * 
*/ matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/" + KeychainContract.PATH_UNIFIED, KEY_RINGS_UNIFIED); + matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + + "/" + KeychainContract.PATH_PUBLIC, + KEY_RINGS_PUBLIC); /** - * select from key_ring + * list key_ring specifics * *
          * key_rings/_/unified
@@ -215,45 +211,44 @@ public class KeychainProvider extends ContentProvider {
             case KEY_RING_UNIFIED:
             case KEY_RINGS_UNIFIED: {
                 HashMap projectionMap = new HashMap();
-                projectionMap.put(BaseColumns._ID, Tables.KEYS + ".oid AS _id");
-                projectionMap.put(KeysColumns.MASTER_KEY_ID, Tables.KEYS + "." + KeysColumns.MASTER_KEY_ID);
-                projectionMap.put(KeysColumns.RANK, Tables.KEYS + "." + KeysColumns.RANK);
-                projectionMap.put(KeysColumns.KEY_ID, KeysColumns.KEY_ID);
-                projectionMap.put(KeysColumns.KEY_SIZE, KeysColumns.KEY_SIZE);
-                projectionMap.put(KeysColumns.IS_REVOKED, KeysColumns.IS_REVOKED);
-                projectionMap.put(KeysColumns.CAN_CERTIFY, KeysColumns.CAN_CERTIFY);
-                projectionMap.put(KeysColumns.CAN_ENCRYPT, KeysColumns.CAN_ENCRYPT);
-                projectionMap.put(KeysColumns.CAN_SIGN, KeysColumns.CAN_SIGN);
-                projectionMap.put(KeysColumns.CREATION, KeysColumns.CREATION);
-                projectionMap.put(KeysColumns.EXPIRY, KeysColumns.EXPIRY);
-                projectionMap.put(KeysColumns.ALGORITHM, KeysColumns.ALGORITHM);
-                projectionMap.put(KeysColumns.FINGERPRINT, KeysColumns.FINGERPRINT);
-                projectionMap.put(UserIdsColumns.USER_ID, UserIdsColumns.USER_ID);
-                projectionMap.put(Tables.KEY_RINGS_SECRET + "." + KeyRings.MASTER_KEY_ID, Tables.KEY_RINGS_SECRET + "." + KeyRingsColumns.MASTER_KEY_ID);
+                projectionMap.put(KeyRings._ID, Tables.KEYS + ".oid AS _id");
+                projectionMap.put(KeyRings.MASTER_KEY_ID, Tables.KEYS + "." + Keys.MASTER_KEY_ID);
+                projectionMap.put(KeyRings.KEY_ID, Keys.KEY_ID);
+                projectionMap.put(KeyRings.KEY_SIZE, Keys.KEY_SIZE);
+                projectionMap.put(KeyRings.IS_REVOKED, Keys.IS_REVOKED);
+                projectionMap.put(KeyRings.CAN_CERTIFY, Keys.CAN_CERTIFY);
+                projectionMap.put(KeyRings.CAN_ENCRYPT, Keys.CAN_ENCRYPT);
+                projectionMap.put(KeyRings.CAN_SIGN, Keys.CAN_SIGN);
+                projectionMap.put(KeyRings.CREATION, Keys.CREATION);
+                projectionMap.put(KeyRings.EXPIRY, Keys.EXPIRY);
+                projectionMap.put(KeyRings.ALGORITHM, Keys.ALGORITHM);
+                projectionMap.put(KeyRings.FINGERPRINT, Keys.FINGERPRINT);
+                projectionMap.put(KeyRings.USER_ID, UserIds.USER_ID);
+                projectionMap.put(KeyRings.HAS_SECRET, "(" + Tables.KEY_RINGS_SECRET + "." + KeyRings.MASTER_KEY_ID + " IS NOT NULL) AS " + KeyRings.HAS_SECRET);
                 qb.setProjectionMap(projectionMap);
 
                 qb.setTables(
                     Tables.KEYS
                         + " INNER JOIN " + Tables.USER_IDS + " ON ("
-                                    + Tables.KEYS + "." + KeysColumns.MASTER_KEY_ID
+                                    + Tables.KEYS + "." + Keys.MASTER_KEY_ID
                                 + " = "
-                                    + Tables.USER_IDS + "." + UserIdsColumns.MASTER_KEY_ID
-                            + " AND " + Tables.USER_IDS + "." + UserIdsColumns.RANK + " = 0"
+                                    + Tables.USER_IDS + "." + UserIds.MASTER_KEY_ID
+                            + " AND " + Tables.USER_IDS + "." + UserIds.RANK + " = 0"
                         + ") LEFT JOIN " + Tables.KEY_RINGS_SECRET + " ON ("
-                            + Tables.KEYS + "." + KeysColumns.MASTER_KEY_ID
+                            + Tables.KEYS + "." + Keys.MASTER_KEY_ID
                                 + " = "
-                            + Tables.KEY_RINGS_SECRET + "." + KeyRingsColumns.MASTER_KEY_ID
+                            + Tables.KEY_RINGS_SECRET + "." + KeyRings.MASTER_KEY_ID
                         + ")"
                     );
-                qb.appendWhere(Tables.KEYS + "." + KeysColumns.RANK + " = 0");
+                qb.appendWhere(Tables.KEYS + "." + Keys.RANK + " = 0");
 
                 if(match == KEY_RING_UNIFIED) {
-                    qb.appendWhere(" AND " + Tables.KEYS + "." + KeysColumns.MASTER_KEY_ID + " = ");
+                    qb.appendWhere(" AND " + Tables.KEYS + "." + Keys.MASTER_KEY_ID + " = ");
                     qb.appendWhereEscapeString(uri.getPathSegments().get(1));
                 } else if (TextUtils.isEmpty(sortOrder)) {
                     sortOrder =
                             Tables.KEY_RINGS_SECRET + "." + KeyRings.MASTER_KEY_ID + " IS NULL DESC"
-                            + Tables.USER_IDS + "." + UserIdsColumns.USER_ID + " ASC";
+                            + Tables.USER_IDS + "." + UserIds.USER_ID + " ASC";
                 }
 
                 // uri to watch is all /key_rings/
@@ -276,38 +271,38 @@ public class KeychainProvider extends ContentProvider {
                     if (i != 0) {
                         emailWhere += " OR ";
                     }
-                    emailWhere += "tmp." + UserIdsColumns.USER_ID + " LIKE ";
+                    emailWhere += "tmp." + UserIds.USER_ID + " LIKE ";
                     // match '*', so it has to be at the *end* of the user id
                     emailWhere += DatabaseUtils.sqlEscapeString("%<" + chunks[i] + ">");
                     gotCondition = true;
                 }
 
                 if (gotCondition) {
-                    qb.appendWhere(" AND EXISTS (SELECT tmp." + BaseColumns._ID + " FROM "
-                            + Tables.USER_IDS + " AS tmp WHERE tmp." + UserIdsColumns.KEY_RING_ROW_ID
-                            + " = " + Tables.KEY_RINGS + "." + BaseColumns._ID + " AND (" + emailWhere
+                    qb.appendWhere(" AND EXISTS (SELECT tmp." + Base._ID + " FROM "
+                            + Tables.USER_IDS + " AS tmp WHERE tmp." + UserIds.KEY_RING_ROW_ID
+                            + " = " + Tables.KEY_RINGS + "." + Base._ID + " AND (" + emailWhere
                             + "))");
                 }*/
 
             case KEY_RING_KEYS: {
                 HashMap projectionMap = new HashMap();
-                projectionMap.put(BaseColumns._ID, Tables.KEYS + ".oid AS _id");
-                projectionMap.put(KeysColumns.MASTER_KEY_ID, Tables.KEYS + "." + KeysColumns.MASTER_KEY_ID);
-                projectionMap.put(KeysColumns.RANK, Tables.KEYS + "." + KeysColumns.RANK);
-                projectionMap.put(KeysColumns.KEY_ID, KeysColumns.KEY_ID);
-                projectionMap.put(KeysColumns.KEY_SIZE, KeysColumns.KEY_SIZE);
-                projectionMap.put(KeysColumns.IS_REVOKED, KeysColumns.IS_REVOKED);
-                projectionMap.put(KeysColumns.CAN_CERTIFY, KeysColumns.CAN_CERTIFY);
-                projectionMap.put(KeysColumns.CAN_ENCRYPT, KeysColumns.CAN_ENCRYPT);
-                projectionMap.put(KeysColumns.CAN_SIGN, KeysColumns.CAN_SIGN);
-                projectionMap.put(KeysColumns.CREATION, KeysColumns.CREATION);
-                projectionMap.put(KeysColumns.EXPIRY, KeysColumns.EXPIRY);
-                projectionMap.put(KeysColumns.ALGORITHM, KeysColumns.ALGORITHM);
-                projectionMap.put(KeysColumns.FINGERPRINT, KeysColumns.FINGERPRINT);
+                projectionMap.put(Keys._ID, Tables.KEYS + ".oid AS _id");
+                projectionMap.put(Keys.MASTER_KEY_ID, Tables.KEYS + "." + Keys.MASTER_KEY_ID);
+                projectionMap.put(Keys.RANK, Tables.KEYS + "." + Keys.RANK);
+                projectionMap.put(Keys.KEY_ID, Keys.KEY_ID);
+                projectionMap.put(Keys.KEY_SIZE, Keys.KEY_SIZE);
+                projectionMap.put(Keys.IS_REVOKED, Keys.IS_REVOKED);
+                projectionMap.put(Keys.CAN_CERTIFY, Keys.CAN_CERTIFY);
+                projectionMap.put(Keys.CAN_ENCRYPT, Keys.CAN_ENCRYPT);
+                projectionMap.put(Keys.CAN_SIGN, Keys.CAN_SIGN);
+                projectionMap.put(Keys.CREATION, Keys.CREATION);
+                projectionMap.put(Keys.EXPIRY, Keys.EXPIRY);
+                projectionMap.put(Keys.ALGORITHM, Keys.ALGORITHM);
+                projectionMap.put(Keys.FINGERPRINT, Keys.FINGERPRINT);
                 qb.setProjectionMap(projectionMap);
 
                 qb.setTables(Tables.KEYS);
-                qb.appendWhere(KeysColumns.MASTER_KEY_ID + " = ");
+                qb.appendWhere(Keys.MASTER_KEY_ID + " = ");
                 qb.appendWhereEscapeString(uri.getPathSegments().get(1));
 
                 break;
@@ -315,7 +310,7 @@ public class KeychainProvider extends ContentProvider {
 
             case KEY_RING_USER_IDS: {
                 HashMap projectionMap = new HashMap();
-                projectionMap.put(BaseColumns._ID, Tables.USER_IDS + ".oid AS _id");
+                projectionMap.put(UserIds._ID, Tables.USER_IDS + ".oid AS _id");
                 projectionMap.put(UserIds.MASTER_KEY_ID, UserIds.MASTER_KEY_ID);
                 projectionMap.put(UserIds.USER_ID, UserIds.USER_ID);
                 projectionMap.put(UserIds.RANK, UserIds.RANK);
@@ -323,36 +318,44 @@ public class KeychainProvider extends ContentProvider {
                 qb.setProjectionMap(projectionMap);
 
                 qb.setTables(Tables.USER_IDS);
-                qb.appendWhere(UserIdsColumns.MASTER_KEY_ID + " = ");
+                qb.appendWhere(UserIds.MASTER_KEY_ID + " = ");
                 qb.appendWhereEscapeString(uri.getPathSegments().get(1));
 
+                if (TextUtils.isEmpty(sortOrder)) {
+                    sortOrder = UserIds.RANK + " ASC";
+                }
+
                 break;
 
             }
 
+            case KEY_RINGS_PUBLIC:
             case KEY_RING_PUBLIC: {
                 HashMap projectionMap = new HashMap();
-                projectionMap.put(BaseColumns._ID, Tables.KEY_RINGS_PUBLIC + ".oid AS _id");
-                projectionMap.put(KeyRings.MASTER_KEY_ID, KeyRings.MASTER_KEY_ID);
-                projectionMap.put(KeyRings.KEY_RING_DATA, KeyRings.KEY_RING_DATA);
+                projectionMap.put(KeyRingData._ID, Tables.KEY_RINGS_PUBLIC + ".oid AS _id");
+                projectionMap.put(KeyRingData.MASTER_KEY_ID, KeyRingData.MASTER_KEY_ID);
+                projectionMap.put(KeyRingData.KEY_RING_DATA, KeyRingData.KEY_RING_DATA);
                 qb.setProjectionMap(projectionMap);
 
                 qb.setTables(Tables.KEY_RINGS_PUBLIC);
-                qb.appendWhere(KeyRingsColumns.MASTER_KEY_ID + " = ");
-                qb.appendWhereEscapeString(uri.getPathSegments().get(1));
+
+                if(match == KEY_RING_PUBLIC) {
+                    qb.appendWhere(KeyRings.MASTER_KEY_ID + " = ");
+                    qb.appendWhereEscapeString(uri.getPathSegments().get(1));
+                }
 
                 break;
             }
 
             case KEY_RING_SECRET: {
                 HashMap projectionMap = new HashMap();
-                projectionMap.put(BaseColumns._ID, Tables.KEY_RINGS_SECRET + ".oid AS _id");
-                projectionMap.put(KeyRings.MASTER_KEY_ID, KeyRings.MASTER_KEY_ID);
-                projectionMap.put(KeyRings.KEY_RING_DATA, KeyRings.KEY_RING_DATA);
+                projectionMap.put(KeyRingData._ID, Tables.KEY_RINGS_SECRET + ".oid AS _id");
+                projectionMap.put(KeyRingData.MASTER_KEY_ID, KeyRingData.MASTER_KEY_ID);
+                projectionMap.put(KeyRingData.KEY_RING_DATA, KeyRingData.KEY_RING_DATA);
                 qb.setProjectionMap(projectionMap);
 
                 qb.setTables(Tables.KEY_RINGS_SECRET);
-                qb.appendWhere(KeyRingsColumns.MASTER_KEY_ID + " = ");
+                qb.appendWhere(KeyRings.MASTER_KEY_ID + " = ");
                 qb.appendWhereEscapeString(uri.getPathSegments().get(1));
 
                 break;
@@ -429,23 +432,23 @@ public class KeychainProvider extends ContentProvider {
             switch (match) {
                 case KEY_RING_PUBLIC:
                     db.insertOrThrow(Tables.KEY_RINGS_PUBLIC, null, values);
-                    keyId = values.getAsLong(KeyRingsColumns.MASTER_KEY_ID);
+                    keyId = values.getAsLong(KeyRings.MASTER_KEY_ID);
                     break;
 
                 case KEY_RING_SECRET:
                     db.insertOrThrow(Tables.KEY_RINGS_SECRET, null, values);
-                    keyId = values.getAsLong(KeyRingsColumns.MASTER_KEY_ID);
+                    keyId = values.getAsLong(KeyRings.MASTER_KEY_ID);
                     break;
 
                 case KEY_RING_KEYS:
                     Log.d(Constants.TAG, "keys");
                     db.insertOrThrow(Tables.KEYS, null, values);
-                    keyId = values.getAsLong(KeysColumns.MASTER_KEY_ID);
+                    keyId = values.getAsLong(Keys.MASTER_KEY_ID);
                     break;
 
                 case KEY_RING_USER_IDS:
                     db.insertOrThrow(Tables.USER_IDS, null, values);
-                    keyId = values.getAsLong(UserIdsColumns.MASTER_KEY_ID);
+                    keyId = values.getAsLong(UserIds.MASTER_KEY_ID);
                     break;
 
                 case API_APPS:
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
index 18eaa375a..339e6a069 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
@@ -43,6 +43,7 @@ import org.sufficientlysecure.keychain.pgp.PgpHelper;
 import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
 import org.sufficientlysecure.keychain.provider.KeychainContract.ApiApps;
 import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
+import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData;
 import org.sufficientlysecure.keychain.provider.KeychainContract.Keys;
 import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds;
 import org.sufficientlysecure.keychain.remote.AccountSettings;
@@ -65,11 +66,11 @@ public class ProviderHelper {
      */
     public static PGPKeyRing getPGPKeyRing(Context context, Uri queryUri) {
         Cursor cursor = context.getContentResolver().query(queryUri,
-                new String[]{KeyRings._ID, KeyRings.KEY_RING_DATA}, null, null, null);
+                new String[]{KeyRings._ID, KeyRingData.KEY_RING_DATA}, null, null, null);
 
         PGPKeyRing keyRing = null;
         if (cursor != null && cursor.moveToFirst()) {
-            int keyRingDataCol = cursor.getColumnIndex(KeyRings.KEY_RING_DATA);
+            int keyRingDataCol = cursor.getColumnIndex(KeyRingData.KEY_RING_DATA);
 
             byte[] data = cursor.getBlob(keyRingDataCol);
             if (data != null) {
@@ -156,7 +157,7 @@ public class ProviderHelper {
      */
     public static PGPPublicKeyRing getPGPPublicKeyRing(Context context,
                                                                     long masterKeyId) {
-        Uri queryUri = KeyRings.buildPublicKeyRingUri(Long.toString(masterKeyId));
+        Uri queryUri = KeyRingData.buildPublicKeyRingUri(Long.toString(masterKeyId));
         return (PGPPublicKeyRing) getPGPKeyRing(context, queryUri);
     }
 
@@ -165,7 +166,7 @@ public class ProviderHelper {
      */
     public static PGPSecretKeyRing getPGPSecretKeyRing(Context context,
                                                                     long masterKeyId) {
-        Uri queryUri = KeyRings.buildSecretKeyRingUri(Long.toString(masterKeyId));
+        Uri queryUri = KeyRingData.buildSecretKeyRingUri(Long.toString(masterKeyId));
         return (PGPSecretKeyRing) getPGPKeyRing(context, queryUri);
     }
 
@@ -178,12 +179,11 @@ public class ProviderHelper {
         long masterKeyId = masterKey.getKeyID();
 
         // IF there is a secret key, preserve it!
-        // TODO This even necessary?
-        // PGPSecretKeyRing secretRing = ProviderHelper.getPGPSecretKeyRing(context, masterKeyId);
+        PGPSecretKeyRing secretRing = ProviderHelper.getPGPSecretKeyRing(context, masterKeyId);
 
         // delete old version of this keyRing, which also deletes all keys and userIds on cascade
         try {
-            context.getContentResolver().delete(KeyRings.buildPublicKeyRingUri(Long.toString(masterKeyId)), null, null);
+            context.getContentResolver().delete(KeyRingData.buildPublicKeyRingUri(Long.toString(masterKeyId)), null, null);
         } catch (UnsupportedOperationException e) {
             Log.e(Constants.TAG, "Key could not be deleted! Maybe we are creating a new one!", e);
         }
@@ -193,11 +193,11 @@ public class ProviderHelper {
         // NOTE: If we would not use the same _ID again,
         // getting back to the ViewKeyActivity would result in Nullpointer,
         // because the currently loaded key would be gone from the database
-        values.put(KeyRings.MASTER_KEY_ID, masterKeyId);
-        values.put(KeyRings.KEY_RING_DATA, keyRing.getEncoded());
+        values.put(KeyRingData.MASTER_KEY_ID, masterKeyId);
+        values.put(KeyRingData.KEY_RING_DATA, keyRing.getEncoded());
 
         // insert new version of this keyRing
-        Uri uri = KeyRings.buildPublicKeyRingUri(Long.toString(masterKeyId));
+        Uri uri = KeyRingData.buildPublicKeyRingUri(Long.toString(masterKeyId));
         Uri insertedUri = context.getContentResolver().insert(uri, values);
 
         // save all keys and userIds included in keyRing object in database
@@ -233,31 +233,43 @@ public class ProviderHelper {
         }
 
         // Save the saved keyring (if any)
-        // TODO this even necessary? see above...
-        // if(secretRing != null)
-            // saveKeyRing(context, secretRing);
+        if(secretRing != null) {
+            saveKeyRing(context, secretRing);
+        }
 
     }
 
     /**
-     * Saves PGPSecretKeyRing with its keys and userIds in DB
+     * Saves a PGPSecretKeyRing in the DB. This will only work if a corresponding public keyring
+     * is already in the database!
      */
     @SuppressWarnings("unchecked")
     public static void saveKeyRing(Context context, PGPSecretKeyRing keyRing) throws IOException {
-        PGPSecretKey masterKey = keyRing.getSecretKey();
-        long masterKeyId = masterKey.getKeyID();
+        long masterKeyId = keyRing.getPublicKey().getKeyID();
 
-        // TODO Make sure there is a public key for this secret key in the db (create one maybe)
+        // save secret keyring
+        ContentValues values = new ContentValues();
+        values.put(KeyRingData.MASTER_KEY_ID, masterKeyId);
+        values.put(KeyRingData.KEY_RING_DATA, keyRing.getEncoded());
+        // insert new version of this keyRing
+        Uri uri = KeyRingData.buildSecretKeyRingUri(Long.toString(masterKeyId));
+        context.getContentResolver().insert(uri, values);
 
-        {
-            ContentValues values = new ContentValues();
-            values.put(KeyRings.MASTER_KEY_ID, masterKeyId);
-            values.put(KeyRings.KEY_RING_DATA, keyRing.getEncoded());
-            // insert new version of this keyRing
-            Uri uri = KeyRings.buildSecretKeyRingUri(Long.toString(masterKeyId));
-            context.getContentResolver().insert(uri, values);
-        }
+    }
 
+    /**
+     * Saves (or updates) a pair of public and secret KeyRings in the database
+     */
+    @SuppressWarnings("unchecked")
+    public static void saveKeyRing(Context context, PGPPublicKeyRing pubRing, PGPSecretKeyRing privRing) throws IOException {
+        long masterKeyId = pubRing.getPublicKey().getKeyID();
+
+        // delete secret keyring (so it isn't unnecessarily saved by public-saveKeyRing below)
+        context.getContentResolver().delete(KeyRingData.buildSecretKeyRingUri(Long.toString(masterKeyId)), null, null);
+
+        // save public keyring
+        saveKeyRing(context, pubRing);
+        saveKeyRing(context, privRing);
     }
 
     /**
@@ -314,24 +326,14 @@ public class ProviderHelper {
         return ContentProviderOperation.newInsert(uri).withValues(values).build();
     }
 
-    public static void deletePublicKeyRing(Context context, long masterKeyId) {
-        ContentResolver cr = context.getContentResolver();
-        cr.delete(KeyRings.buildPublicKeyRingUri(Long.toString(masterKeyId)), null, null);
-    }
-
-    public static void deleteSecretKeyRing(Context context, long masterKeyId) {
-        ContentResolver cr = context.getContentResolver();
-        cr.delete(KeyRings.buildSecretKeyRingUri(Long.toString(masterKeyId)), null, null);
-    }
-
     public static boolean hasSecretKeyByMasterKeyId(Context context, long masterKeyId) {
-        Uri queryUri = KeyRings.buildSecretKeyRingUri(Long.toString(masterKeyId));
+        Uri queryUri = KeyRingData.buildSecretKeyRingUri(Long.toString(masterKeyId));
         // see if we can get our master key id back from the uri
         return getMasterKeyId(context, queryUri) == masterKeyId;
     }
 
-    /**
-     * Get master key id of key
+    /** Find the master key id related to a given query. The id will either be extracted from the
+     * query, which should work for all specific /key_rings/ queries, or will be queried if it can't.
      */
     public static long getMasterKeyId(Context context, Uri queryUri) {
         // try extracting from the uri first
@@ -339,39 +341,25 @@ public class ProviderHelper {
             return Long.parseLong(queryUri.getPathSegments().get(1));
         } catch(NumberFormatException e) {
             // didn't work? oh well.
+            Log.d(Constants.TAG, "Couldn't get masterKeyId from URI, querying...");
         }
-
-        Cursor cursor = context.getContentResolver().query(queryUri, new String[] {
-                KeyRings.MASTER_KEY_ID
-        }, null, null, null);
-
-        long masterKeyId = 0;
-        try {
-            if (cursor != null && cursor.moveToFirst()) {
-                int masterKeyIdCol = cursor.getColumnIndexOrThrow(KeyRings.MASTER_KEY_ID);
-
-                masterKeyId = cursor.getLong(masterKeyIdCol);
-            }
-        } finally {
-            if (cursor != null) {
-                cursor.close();
-            }
-        }
-
-        return masterKeyId;
+        Object data = getUnifiedData(context, queryUri, KeyRings.MASTER_KEY_ID);
+        if(data instanceof Long)
+            return (Long) data;
+        // TODO better error handling?
+        return 0L;
     }
 
-    public static ArrayList getKeyRingsAsArmoredString(Context context, Uri uri,
-                                                               long[] masterKeyIds) {
+    public static ArrayList getKeyRingsAsArmoredString(Context context, long[] masterKeyIds) {
         ArrayList output = new ArrayList();
 
         if (masterKeyIds != null && masterKeyIds.length > 0) {
 
-            Cursor cursor = getCursorWithSelectedKeyringMasterKeyIds(context, uri, masterKeyIds);
+            Cursor cursor = getCursorWithSelectedKeyringMasterKeyIds(context, masterKeyIds);
 
             if (cursor != null) {
-                int masterIdCol = cursor.getColumnIndex(KeyRings.MASTER_KEY_ID);
-                int dataCol = cursor.getColumnIndex(KeyRings.KEY_RING_DATA);
+                int masterIdCol = cursor.getColumnIndex(KeyRingData.MASTER_KEY_ID);
+                int dataCol = cursor.getColumnIndex(KeyRingData.KEY_RING_DATA);
                 if (cursor.moveToFirst()) {
                     do {
                         Log.d(Constants.TAG, "masterKeyId: " + cursor.getLong(masterIdCol));
@@ -421,48 +409,11 @@ public class ProviderHelper {
             return null;
         }
     }
-
-    public static byte[] getKeyRingsAsByteArray(Context context, Uri uri, long[] masterKeyIds) {
-        ByteArrayOutputStream bos = new ByteArrayOutputStream();
-
-        if (masterKeyIds != null && masterKeyIds.length > 0) {
-
-            Cursor cursor = getCursorWithSelectedKeyringMasterKeyIds(context, uri, masterKeyIds);
-
-            if (cursor != null) {
-                int masterIdCol = cursor.getColumnIndex(KeyRings.MASTER_KEY_ID);
-                int dataCol = cursor.getColumnIndex(KeyRings.KEY_RING_DATA);
-                if (cursor.moveToFirst()) {
-                    do {
-                        Log.d(Constants.TAG, "masterKeyId: " + cursor.getLong(masterIdCol));
-
-                        // get actual keyring data blob and write it to ByteArrayOutputStream
-                        try {
-                            bos.write(cursor.getBlob(dataCol));
-                        } catch (IOException e) {
-                            Log.e(Constants.TAG, "IOException", e);
-                        }
-                    } while (cursor.moveToNext());
-                }
-            }
-
-            if (cursor != null) {
-                cursor.close();
-            }
-
-        } else {
-            Log.e(Constants.TAG, "No master keys given!");
-        }
-
-        return bos.toByteArray();
-    }
-
-    private static Cursor getCursorWithSelectedKeyringMasterKeyIds(Context context, Uri baseUri,
-                                                                   long[] masterKeyIds) {
+    private static Cursor getCursorWithSelectedKeyringMasterKeyIds(Context context, long[] masterKeyIds) {
         Cursor cursor = null;
         if (masterKeyIds != null && masterKeyIds.length > 0) {
 
-            String inMasterKeyList = KeyRings.MASTER_KEY_ID + " IN (";
+            String inMasterKeyList = KeyRingData.MASTER_KEY_ID + " IN (";
             for (int i = 0; i < masterKeyIds.length; ++i) {
                 if (i != 0) {
                     inMasterKeyList += ", ";
@@ -471,9 +422,9 @@ public class ProviderHelper {
             }
             inMasterKeyList += ")";
 
-            cursor = context.getContentResolver().query(baseUri,
-                    new String[]{KeyRings._ID, KeyRings.MASTER_KEY_ID, KeyRings.KEY_RING_DATA},
-                    inMasterKeyList, null, null);
+            cursor = context.getContentResolver().query(KeyRingData.buildPublicKeyRingUri(), new String[] {
+                    KeyRingData._ID, KeyRingData.MASTER_KEY_ID, KeyRingData.KEY_RING_DATA
+                }, inMasterKeyList, null, null);
         }
 
         return cursor;
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
index f9e143d87..6ee209c5c 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
@@ -518,8 +518,8 @@ public class KeychainIntentService extends IntentService
                     PgpKeyOperation.Pair pair =
                         keyOperations.buildSecretKey(privkey, pubkey, saveParams);
                     setProgress(R.string.progress_saving_key_ring, 90, 100);
-                    ProviderHelper.saveKeyRing(this, pair.first);
-                    ProviderHelper.saveKeyRing(this, pair.second);
+                    // save the pair
+                    ProviderHelper.saveKeyRing(this, pair.second, pair.first);
                     setProgress(R.string.progress_done, 100, 100);
                 }
                 PassphraseCacheService.addCachedPassphrase(this, masterKeyId, newPassphrase);
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java
index 0caf60aa1..e6fd59d55 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java
@@ -57,6 +57,7 @@ import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
 import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
 import org.sufficientlysecure.keychain.provider.KeychainContract;
 import org.sufficientlysecure.keychain.provider.ProviderHelper;
+import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData;
 import org.sufficientlysecure.keychain.service.KeychainIntentService;
 import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
 import org.sufficientlysecure.keychain.service.PassphraseCacheService;
@@ -345,7 +346,7 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener
                 }
                 return true;
             case R.id.menu_key_edit_delete:
-                Uri convertUri = KeychainContract.KeyRings.buildSecretKeyRingUri(mDataUri);
+                Uri convertUri = KeyRingData.buildSecretKeyRingUri(mDataUri);
                     // Message is received after key is deleted
                     Handler returnHandler = new Handler() {
                         @Override
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java
index cc0abe48a..ecd742896 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java
@@ -58,12 +58,9 @@ import org.sufficientlysecure.keychain.Id;
 import org.sufficientlysecure.keychain.R;
 import org.sufficientlysecure.keychain.helper.ExportHelper;
 import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
-import org.sufficientlysecure.keychain.provider.KeychainContract;
 import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
-import org.sufficientlysecure.keychain.provider.KeychainContract.KeyTypes;
+import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData;
 import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds;
-import org.sufficientlysecure.keychain.provider.KeychainDatabase;
-import org.sufficientlysecure.keychain.provider.ProviderHelper;
 import org.sufficientlysecure.keychain.ui.adapter.HighlightQueryCursorAdapter;
 import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment;
 import org.sufficientlysecure.keychain.util.Log;
@@ -257,11 +254,11 @@ public class KeyListFragment extends Fragment
 
     // These are the rows that we will retrieve.
     static final String[] PROJECTION = new String[]{
-            KeychainContract.KeyRings._ID,
-            KeychainContract.Keys.MASTER_KEY_ID,
-            KeychainContract.UserIds.USER_ID,
-            KeychainContract.Keys.IS_REVOKED,
-            KeychainDatabase.Tables.KEY_RINGS_SECRET + "." + KeychainContract.KeyRings.MASTER_KEY_ID
+            KeyRings._ID,
+            KeyRings.MASTER_KEY_ID,
+            KeyRings.USER_ID,
+            KeyRings.IS_REVOKED,
+            KeyRings.HAS_SECRET
     };
 
     static final int INDEX_MASTER_KEY_ID = 1;
@@ -269,11 +266,8 @@ public class KeyListFragment extends Fragment
     static final int INDEX_IS_REVOKED = 3;
     static final int INDEX_HAS_SECRET = 4;
 
-    static final String SORT_ORDER =
-            // show secret before public key
-            KeychainDatabase.Tables.KEY_RINGS_SECRET + "." + KeychainContract.KeyRings.MASTER_KEY_ID + " IS NULL ASC, " +
-                    // sort by user id otherwise
-                    UserIds.USER_ID + " ASC";
+    // show secret before public key, sort by user id otherwise
+    static final String SORT_ORDER = KeyRings.HAS_SECRET + " DESC, " + UserIds.USER_ID + " ASC";
 
     @Override
     public Loader onCreateLoader(int id, Bundle args) {
@@ -283,7 +277,7 @@ public class KeyListFragment extends Fragment
         String where = null;
         String whereArgs[] = null;
         if (mCurQuery != null) {
-            where = KeychainContract.UserIds.USER_ID + " LIKE ?";
+            where = KeyRings.USER_ID + " LIKE ?";
             whereArgs = new String[]{"%" + mCurQuery + "%"};
         }
         // Now create and return a CursorLoader that will take care of
@@ -329,17 +323,15 @@ public class KeyListFragment extends Fragment
             viewIntent = new Intent(getActivity(), ViewKeyActivityJB.class);
         }
         viewIntent.setData(
-                KeychainContract
-                        .KeyRings.buildGenericKeyRingUri(
-                                            Long.toString(mAdapter.getMasterKeyId(position))));
+                KeyRings.buildGenericKeyRingUri(Long.toString(mAdapter.getMasterKeyId(position))));
         startActivity(viewIntent);
     }
 
     @TargetApi(11)
-    protected void encrypt(ActionMode mode, long[] keyRingMasterKeyIds) {
+    protected void encrypt(ActionMode mode, long[] masterKeyIds) {
         Intent intent = new Intent(getActivity(), EncryptActivity.class);
         intent.setAction(EncryptActivity.ACTION_ENCRYPT);
-        intent.putExtra(EncryptActivity.EXTRA_ENCRYPTION_KEY_IDS, keyRingMasterKeyIds);
+        intent.putExtra(EncryptActivity.EXTRA_ENCRYPTION_KEY_IDS, masterKeyIds);
         // used instead of startActivity set actionbar based on callingPackage
         startActivityForResult(intent, 0);
 
@@ -507,7 +499,7 @@ public class KeyListFragment extends Fragment
                 Button button = (Button) view.findViewById(R.id.edit);
                 TextView revoked = (TextView) view.findViewById(R.id.revoked);
 
-                if (!cursor.isNull(KeyListFragment.INDEX_HAS_SECRET)) {
+                if (cursor.getInt(KeyListFragment.INDEX_HAS_SECRET) != 0) {
                     // this is a secret key - show the edit button
                     statusDivider.setVisibility(View.VISIBLE);
                     statusLayout.setVisibility(View.VISIBLE);
@@ -518,9 +510,7 @@ public class KeyListFragment extends Fragment
                     button.setOnClickListener(new OnClickListener() {
                         public void onClick(View view) {
                             Intent editIntent = new Intent(getActivity(), EditKeyActivity.class);
-                            editIntent.setData(
-                                    KeychainContract.KeyRings
-                                            .buildSecretKeyRingUri(Long.toString(id)));
+                            editIntent.setData(KeyRingData.buildSecretKeyRingUri(Long.toString(id)));
                             editIntent.setAction(EditKeyActivity.ACTION_EDIT_KEY);
                             startActivityForResult(editIntent, 0);
                         }
@@ -581,7 +571,7 @@ public class KeyListFragment extends Fragment
                 throw new IllegalStateException("couldn't move cursor to position " + position);
             }
 
-            if (!mCursor.isNull(KeyListFragment.INDEX_HAS_SECRET)) {
+            if (mCursor.getInt(KeyListFragment.INDEX_HAS_SECRET) != 0) {
                 { // set contact count
                     int num = mCursor.getCount();
                     String contactsTotal = getResources().getQuantityString(R.plurals.n_contacts, num, num);
@@ -621,7 +611,7 @@ public class KeyListFragment extends Fragment
             }
 
             // early breakout: all secret keys are assigned id 0
-            if (!mCursor.isNull(KeyListFragment.INDEX_HAS_SECRET)) {
+            if (mCursor.getInt(KeyListFragment.INDEX_HAS_SECRET) != 0) {
                 return 1L;
             }
             // otherwise, return the first character of the name as ID
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java
index 2437270e5..b60e75fa9 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java
@@ -185,8 +185,8 @@ public class ViewKeyActivity extends ActionBarActivity {
         } else {
             // get public keyring as ascii armored string
             long masterKeyId = ProviderHelper.getMasterKeyId(this, dataUri);
-            ArrayList keyringArmored = ProviderHelper.getKeyRingsAsArmoredString(this,
-                    dataUri, new long[]{masterKeyId});
+            ArrayList keyringArmored = ProviderHelper.getKeyRingsAsArmoredString(
+                    this, new long[]{ masterKeyId });
 
             content = keyringArmored.get(0);
 
@@ -216,8 +216,8 @@ public class ViewKeyActivity extends ActionBarActivity {
     private void copyToClipboard(Uri dataUri) {
         // get public keyring as ascii armored string
         long masterKeyId = ProviderHelper.getMasterKeyId(this, dataUri);
-        ArrayList keyringArmored = ProviderHelper.getKeyRingsAsArmoredString(this, dataUri,
-                new long[]{masterKeyId});
+        ArrayList keyringArmored = ProviderHelper.getKeyRingsAsArmoredString(
+                this, new long[]{ masterKeyId });
 
         ClipboardReflection.copyToClipboard(this, keyringArmored.get(0));
         Toast.makeText(getApplicationContext(), R.string.key_copied_to_clipboard, Toast.LENGTH_LONG)
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java
index 75853ac2a..616200800 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java
@@ -38,7 +38,10 @@ import com.beardedhen.androidbootstrap.BootstrapButton;
 import org.sufficientlysecure.keychain.Constants;
 import org.sufficientlysecure.keychain.R;
 import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
-import org.sufficientlysecure.keychain.provider.KeychainContract;
+import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
+import org.sufficientlysecure.keychain.provider.KeychainContract.Keys;
+import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds;
+import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData;
 import org.sufficientlysecure.keychain.provider.ProviderHelper;
 import org.sufficientlysecure.keychain.ui.adapter.ViewKeyKeysAdapter;
 import org.sufficientlysecure.keychain.ui.adapter.ViewKeyUserIdsAdapter;
@@ -124,6 +127,7 @@ public class ViewKeyMainFragment extends Fragment implements
 
         { // label whether secret key is available, and edit button if it is
             final long masterKeyId = ProviderHelper.getMasterKeyId(getActivity(), mDataUri);
+            // TODO do this some other way...
             if (ProviderHelper.hasSecretKeyByMasterKeyId(getActivity(), masterKeyId)) {
                 // set this attribute. this is a LITTLE unclean, but we have the info available
                 // right here, so why not.
@@ -141,8 +145,7 @@ public class ViewKeyMainFragment extends Fragment implements
                     public void onClick(View view) {
                         Intent editIntent = new Intent(getActivity(), EditKeyActivity.class);
                         editIntent.setData(
-                                KeychainContract
-                                        .KeyRings.buildSecretKeyRingUri(
+                                KeyRingData.buildSecretKeyRingUri(
                                         Long.toString(masterKeyId)));
                         editIntent.setAction(EditKeyActivity.ACTION_EDIT_KEY);
                         startActivityForResult(editIntent, 0);
@@ -161,7 +164,7 @@ public class ViewKeyMainFragment extends Fragment implements
             // TODO see todo note above, doing this here for now
             mActionCertify.setOnClickListener(new View.OnClickListener() {
                 public void onClick(View view) {
-                    certifyKey(KeychainContract.KeyRings.buildGenericKeyRingUri(
+                    certifyKey(KeyRings.buildGenericKeyRingUri(
                             Long.toString(masterKeyId)
                     ));
                 }
@@ -190,31 +193,26 @@ public class ViewKeyMainFragment extends Fragment implements
     }
 
     static final String[] USER_IDS_PROJECTION =
-            new String[]{
-                    KeychainContract.UserIds._ID,
-                    KeychainContract.UserIds.USER_ID,
-                    KeychainContract.UserIds.RANK,
+            new String[] {
+                    UserIds._ID,
+                    UserIds.USER_ID,
+                    UserIds.RANK,
             };
     static final int INDEX_UID_UID = 1;
-    static final String USER_IDS_SORT_ORDER =
-            KeychainContract.UserIds.RANK + " COLLATE LOCALIZED ASC";
-
-    static final String[] KEYS_PROJECTION =
-            new String[]{KeychainContract.Keys._ID, KeychainContract.Keys.KEY_ID,
-                    KeychainContract.Keys.ALGORITHM, KeychainContract.Keys.RANK,
-                    KeychainContract.Keys.KEY_SIZE, KeychainContract.Keys.CAN_CERTIFY,
-                    KeychainContract.Keys.CAN_SIGN, KeychainContract.Keys.CAN_ENCRYPT,
-                    KeychainContract.Keys.IS_REVOKED, KeychainContract.Keys.CREATION,
-                    KeychainContract.Keys.EXPIRY, KeychainContract.Keys.FINGERPRINT};
-    static final String KEYS_SORT_ORDER = KeychainContract.Keys.RANK + " ASC";
+
+    static final String[] KEYS_PROJECTION = new String[] {
+            Keys._ID,
+            Keys.KEY_ID, Keys.RANK,
+            Keys.ALGORITHM, Keys.KEY_SIZE,
+            Keys.CAN_CERTIFY, Keys.CAN_ENCRYPT,
+            Keys.CAN_SIGN, Keys.IS_REVOKED,
+            Keys.CREATION, Keys.EXPIRY,
+            Keys.FINGERPRINT
+    };
     static final int KEYS_INDEX_KEY_ID = 1;
-    static final int KEYS_INDEX_ALGORITHM = 2;
-    static final int KEYS_INDEX_RANK = 3;
+    static final int KEYS_INDEX_ALGORITHM = 3;
     static final int KEYS_INDEX_KEY_SIZE = 4;
-    static final int KEYS_INDEX_CAN_CERTIFY = 5;
-    static final int KEYS_INDEX_CAN_SIGN = 6;
-    static final int KEYS_INDEX_CAN_ENCRYPT = 7;
-    static final int KEYS_INDEX_IS_REVOKED = 8;
+    static final int KEYS_INDEX_CAN_ENCRYPT = 6;
     static final int KEYS_INDEX_CREATION = 9;
     static final int KEYS_INDEX_EXPIRY = 10;
     static final int KEYS_INDEX_FINGERPRINT = 11;
@@ -222,19 +220,18 @@ public class ViewKeyMainFragment extends Fragment implements
     public Loader onCreateLoader(int id, Bundle args) {
         switch (id) {
             case LOADER_ID_USER_IDS: {
-                Uri baseUri = KeychainContract.UserIds.buildUserIdsUri(mDataUri);
+                Uri baseUri = UserIds.buildUserIdsUri(mDataUri);
 
                 // Now create and return a CursorLoader that will take care of
                 // creating a Cursor for the data being displayed.
-                return new CursorLoader(getActivity(), baseUri, USER_IDS_PROJECTION, null, null,
-                        USER_IDS_SORT_ORDER);
+                return new CursorLoader(getActivity(), baseUri, USER_IDS_PROJECTION, null, null, null);
             }
             case LOADER_ID_KEYS: {
-                Uri baseUri = KeychainContract.Keys.buildKeysUri(mDataUri);
+                Uri baseUri = Keys.buildKeysUri(mDataUri);
 
                 // Now create and return a CursorLoader that will take care of
                 // creating a Cursor for the data being displayed.
-                return new CursorLoader(getActivity(), baseUri, KEYS_PROJECTION, null, null, KEYS_SORT_ORDER);
+                return new CursorLoader(getActivity(), baseUri, KEYS_PROJECTION, null, null, null);
             }
 
             default:
@@ -343,7 +340,7 @@ public class ViewKeyMainFragment extends Fragment implements
 
     private void encryptToContact(Uri dataUri) {
         // TODO preselect from uri? should be feasible without trivial query
-        long keyId = Long.parseLong(dataUri.getPathSegments().get(1));
+        long keyId = ProviderHelper.getMasterKeyId(getActivity(), dataUri);
 
         long[] encryptionKeyIds = new long[]{ keyId };
         Intent intent = new Intent(getActivity(), EncryptActivity.class);
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java
index 57dbb7794..feaa0b4cd 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java
@@ -20,8 +20,6 @@ package org.sufficientlysecure.keychain.ui.dialog;
 import android.app.AlertDialog;
 import android.app.Dialog;
 import android.content.DialogInterface;
-import android.database.Cursor;
-import android.net.Uri;
 import android.os.Bundle;
 import android.os.Message;
 import android.os.Messenger;
@@ -35,14 +33,13 @@ import android.widget.LinearLayout;
 import android.widget.TextView;
 
 import org.sufficientlysecure.keychain.Constants;
-import org.sufficientlysecure.keychain.Id;
 import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.provider.KeychainContract;
+import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData;
+import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
 import org.sufficientlysecure.keychain.provider.KeychainDatabase;
 import org.sufficientlysecure.keychain.provider.ProviderHelper;
 import org.sufficientlysecure.keychain.util.Log;
 
-import java.util.ArrayList;
 import java.util.HashMap;
 
 public class DeleteKeyDialogFragment extends DialogFragment {
@@ -107,13 +104,11 @@ public class DeleteKeyDialogFragment extends DialogFragment {
             long masterKeyId = masterKeyIds[0];
 
             HashMap data = ProviderHelper.getUnifiedData(activity, masterKeyId, new String[]{
-                    KeychainContract.UserIds.USER_ID,
-                    KeychainDatabase.Tables.KEY_RINGS_SECRET + "." + KeychainContract.KeyRings.MASTER_KEY_ID
+                    KeyRings.USER_ID,
+                    KeyRings.HAS_SECRET
             });
-            String userId = (String) data.get(KeychainContract.UserIds.USER_ID);
-            boolean hasSecret = data.get(
-                    KeychainDatabase.Tables.KEY_RINGS_SECRET + "." + KeychainContract.KeyRings.MASTER_KEY_ID
-            ) instanceof Long;
+            String userId = (String) data.get(KeyRings.USER_ID);
+            boolean hasSecret = ((Long) data.get(KeyRings.HAS_SECRET)) == 1;
 
             // Hide the Checkbox and TextView since this is a single selection,user will be notified through message
             mDeleteSecretKeyView.setVisibility(View.GONE);
@@ -136,7 +131,7 @@ public class DeleteKeyDialogFragment extends DialogFragment {
                 boolean success = false;
                 for(long masterKeyId : masterKeyIds) {
                     int count = activity.getContentResolver().delete(
-                            KeychainContract.KeyRings.buildPublicKeyRingUri(Long.toString(masterKeyId)), null, null
+                            KeyRingData.buildPublicKeyRingUri(Long.toString(masterKeyId)), null, null
                         );
                     if(count > 0)
                     success = true;
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareQrCodeDialogFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareQrCodeDialogFragment.java
index 1b81c8b3b..dc9fa6235 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareQrCodeDialogFragment.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareQrCodeDialogFragment.java
@@ -107,7 +107,7 @@ public class ShareQrCodeDialogFragment extends DialogFragment {
             long masterKeyId = ProviderHelper.getMasterKeyId(getActivity(), dataUri);
             // get public keyring as ascii armored string
             ArrayList keyringArmored = ProviderHelper.getKeyRingsAsArmoredString(
-                    getActivity(), dataUri, new long[] { masterKeyId });
+                    getActivity(), new long[] { masterKeyId });
 
             // TODO: binary?
 
-- 
cgit v1.2.3


From 59f4b4e3e7cc27981e66f140030bef9a3fce3d25 Mon Sep 17 00:00:00 2001
From: Vincent Breitmoser 
Date: Fri, 4 Apr 2014 01:04:28 +0200
Subject: db-overhaul: minor stuff, mostly ProviderHelper

---
 .../keychain/pgp/PgpDecryptVerify.java             |   6 +-
 .../keychain/provider/ProviderHelper.java          | 119 ++++++++++-----------
 .../keychain/remote/OpenPgpService.java            |   7 +-
 .../keychain/ui/EncryptAsymmetricFragment.java     |   4 +-
 .../keychain/ui/KeyListFragment.java               |   5 +-
 .../keychain/ui/ViewKeyActivity.java               |   4 +-
 .../ui/dialog/PassphraseDialogFragment.java        |   2 +-
 .../ui/dialog/ShareQrCodeDialogFragment.java       |   4 +-
 8 files changed, 73 insertions(+), 78 deletions(-)

(limited to 'OpenPGP-Keychain/src')

diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java
index 77edd353c..4b0a07d9b 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java
@@ -232,7 +232,7 @@ public class PgpDecryptVerify {
                 updateProgress(R.string.progress_finding_key, currentProgress, 100);
 
                 PGPPublicKeyEncryptedData encData = (PGPPublicKeyEncryptedData) obj;
-                secretKey = ProviderHelper.getPGPSecretKeyByKeyId(mContext, encData.getKeyID());
+                secretKey = ProviderHelper.getPGPSecretKeyRing(mContext, encData.getKeyID()).getSecretKey();
                 if (secretKey != null) {
                     // secret key exists in database
 
@@ -362,7 +362,7 @@ public class PgpDecryptVerify {
             for (int i = 0; i < sigList.size(); ++i) {
                 signature = sigList.get(i);
                 signatureKey = ProviderHelper
-                        .getPGPPublicKeyByKeyId(mContext, signature.getKeyID());
+                        .getPGPPublicKeyRing(mContext, signature.getKeyID()).getPublicKey();
                 if (signatureKeyId == 0) {
                     signatureKeyId = signature.getKeyID();
                 }
@@ -546,7 +546,7 @@ public class PgpDecryptVerify {
         PGPPublicKey signatureKey = null;
         for (int i = 0; i < sigList.size(); ++i) {
             signature = sigList.get(i);
-            signatureKey = ProviderHelper.getPGPPublicKeyByKeyId(mContext, signature.getKeyID());
+            signatureKey = ProviderHelper.getPGPPublicKeyRing(mContext, signature.getKeyID()).getPublicKey();
             if (signatureKeyId == 0) {
                 signatureKeyId = signature.getKeyID();
             }
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
index 339e6a069..a81368988 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
@@ -61,44 +61,10 @@ import java.util.Set;
 
 public class ProviderHelper {
 
-    /**
-     * Private helper method to get PGPKeyRing from database
-     */
-    public static PGPKeyRing getPGPKeyRing(Context context, Uri queryUri) {
-        Cursor cursor = context.getContentResolver().query(queryUri,
-                new String[]{KeyRings._ID, KeyRingData.KEY_RING_DATA}, null, null, null);
-
-        PGPKeyRing keyRing = null;
-        if (cursor != null && cursor.moveToFirst()) {
-            int keyRingDataCol = cursor.getColumnIndex(KeyRingData.KEY_RING_DATA);
-
-            byte[] data = cursor.getBlob(keyRingDataCol);
-            if (data != null) {
-                keyRing = PgpConversionHelper.BytesToPGPKeyRing(data);
-            }
-        }
-
-        if (cursor != null) {
-            cursor.close();
-        }
-
-        return keyRing;
+    public static Object getGenericData(Context context, Uri uri, String column) {
+        return getGenericData(context, uri, new String[] { column }).get(column);
     }
-
-    public static Object getUnifiedData(Context context, long masterKeyId, String column) {
-        return getUnifiedData(context, masterKeyId, new String[] { column }).get(column);
-    }
-    public static Object getUnifiedData(Context context, Uri uri, String column) {
-        return getUnifiedData(context, uri, new String[] { column }).get(column);
-    }
-
-    public static HashMap getUnifiedData(Context context, long masterKeyId, String[] proj) {
-        return getUnifiedData(context, KeyRings.buildGenericKeyRingUri(Long.toString(masterKeyId)), proj);
-    }
-
-    public static HashMap getUnifiedData(Context context, Uri uri, String[] proj) {
-        uri = KeyRings.buildUnifiedKeyRingUri(uri);
-
+    public static HashMap getGenericData(Context context, Uri uri, String[] proj) {
         Cursor cursor = context.getContentResolver().query(uri, proj, null, null, null);
 
         HashMap result = new HashMap(proj.length);
@@ -135,20 +101,65 @@ public class ProviderHelper {
         return result;
     }
 
+    public static Object getUnifiedData(Context context, long masterKeyId, String column) {
+        return getUnifiedData(context, masterKeyId, new String[] { column }).get(column);
+    }
+    public static HashMap getUnifiedData(Context context, long masterKeyId, String[] proj) {
+        return getGenericData(context, KeyRings.buildUnifiedKeyRingUri(Long.toString(masterKeyId)), proj);
+    }
 
-    public static PGPPublicKey getPGPPublicKeyByKeyId(Context context, long keyId) {
-        return getPGPPublicKeyRingWithKeyId(context, keyId).getPublicKey(keyId);
+    /** Find the master key id related to a given query. The id will either be extracted from the
+     * query, which should work for all specific /key_rings/ queries, or will be queried if it can't.
+     */
+    public static long getMasterKeyId(Context context, Uri queryUri) {
+        // try extracting from the uri first
+        String firstSegment = queryUri.getPathSegments().get(1);
+        if(!firstSegment.equals("find")) try {
+            return Long.parseLong(firstSegment);
+        } catch(NumberFormatException e) {
+            // didn't work? oh well.
+            Log.d(Constants.TAG, "Couldn't get masterKeyId from URI, querying...");
+        }
+        Object data = getGenericData(context, queryUri, KeyRings.MASTER_KEY_ID);
+        if(data instanceof Long)
+            return (Long) data;
+        // TODO better error handling?
+        return 0L;
     }
-    public static PGPPublicKeyRing getPGPPublicKeyRingWithKeyId(Context context, long keyId) {
-        // todo do
-        return null;
+
+    public static PGPKeyRing getPGPKeyRing(Context context, Uri queryUri) {
+        Cursor cursor = context.getContentResolver().query(queryUri,
+                new String[]{KeyRings._ID, KeyRingData.KEY_RING_DATA}, null, null, null);
+
+        PGPKeyRing keyRing = null;
+        if (cursor != null && cursor.moveToFirst()) {
+            int keyRingDataCol = cursor.getColumnIndex(KeyRingData.KEY_RING_DATA);
+
+            byte[] data = cursor.getBlob(keyRingDataCol);
+            if (data != null) {
+                keyRing = PgpConversionHelper.BytesToPGPKeyRing(data);
+            }
+        }
+
+        if (cursor != null) {
+            cursor.close();
+        }
+
+        return keyRing;
     }
 
-    public static PGPSecretKey getPGPSecretKeyByKeyId(Context context, long keyId) {
-        return getPGPSecretKeyRingWithKeyId(context, keyId).getSecretKey(keyId);
+    public static PGPPublicKeyRing getPGPPublicKeyRingWithKeyId(Context context, long keyId) {
+        Uri uri = KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(Long.toString(keyId));
+        long masterKeyId = getMasterKeyId(context, uri);
+        if(masterKeyId != 0)
+            return getPGPPublicKeyRing(context, masterKeyId);
+        return null;
     }
     public static PGPSecretKeyRing getPGPSecretKeyRingWithKeyId(Context context, long keyId) {
-        // todo do
+        Uri uri = KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(Long.toString(keyId));
+        long masterKeyId = getMasterKeyId(context, uri);
+        if(masterKeyId != 0)
+            return getPGPSecretKeyRing(context, masterKeyId);
         return null;
     }
 
@@ -332,24 +343,6 @@ public class ProviderHelper {
         return getMasterKeyId(context, queryUri) == masterKeyId;
     }
 
-    /** Find the master key id related to a given query. The id will either be extracted from the
-     * query, which should work for all specific /key_rings/ queries, or will be queried if it can't.
-     */
-    public static long getMasterKeyId(Context context, Uri queryUri) {
-        // try extracting from the uri first
-        try {
-            return Long.parseLong(queryUri.getPathSegments().get(1));
-        } catch(NumberFormatException e) {
-            // didn't work? oh well.
-            Log.d(Constants.TAG, "Couldn't get masterKeyId from URI, querying...");
-        }
-        Object data = getUnifiedData(context, queryUri, KeyRings.MASTER_KEY_ID);
-        if(data instanceof Long)
-            return (Long) data;
-        // TODO better error handling?
-        return 0L;
-    }
-
     public static ArrayList getKeyRingsAsArmoredString(Context context, long[] masterKeyIds) {
         ArrayList output = new ArrayList();
 
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java
index 007fbc99b..ccae6b2f2 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java
@@ -35,7 +35,8 @@ import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify;
 import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyResult;
 import org.sufficientlysecure.keychain.pgp.PgpSignEncrypt;
 import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
-import org.sufficientlysecure.keychain.provider.KeychainContract;
+import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
+import org.sufficientlysecure.keychain.provider.KeychainContract.ApiAccounts;
 import org.sufficientlysecure.keychain.provider.ProviderHelper;
 import org.sufficientlysecure.keychain.remote.ui.RemoteServiceActivity;
 import org.sufficientlysecure.keychain.service.PassphraseCacheService;
@@ -351,7 +352,7 @@ public class OpenPgpService extends RemoteService {
         try {
             long keyId = data.getLongExtra(OpenPgpApi.EXTRA_KEY_ID, 0);
 
-            if (ProviderHelper.getPGPPublicKeyByKeyId(this, keyId) == null) {
+            if (ProviderHelper.getPGPPublicKeyRing(this, keyId) == null) {
                 Intent result = new Intent();
 
                 // If keys are not in db we return an additional PendingIntent
@@ -460,7 +461,7 @@ public class OpenPgpService extends RemoteService {
                 String currentPkg = getCurrentCallingPackage();
                 Set allowedKeyIds =
                     ProviderHelper.getAllKeyIdsForApp(mContext,
-                        KeychainContract.ApiAccounts.buildBaseUri(currentPkg));
+                        ApiAccounts.buildBaseUri(currentPkg));
                 return decryptAndVerifyImpl(data, input, output, allowedKeyIds);
             } else if (OpenPgpApi.ACTION_GET_KEY.equals(action)) {
                 return getKeyImpl(data);
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java
index 0b724d52c..f749a4c1c 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java
@@ -37,7 +37,7 @@ import org.spongycastle.openpgp.PGPSecretKeyRing;
 import org.sufficientlysecure.keychain.Id;
 import org.sufficientlysecure.keychain.R;
 import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
-import org.sufficientlysecure.keychain.provider.KeychainContract;
+import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
 import org.sufficientlysecure.keychain.provider.ProviderHelper;
 
 import java.util.HashMap;
@@ -206,7 +206,7 @@ public class EncryptAsymmetricFragment extends Fragment {
             String uidExtra = "";
             // See if we can get a user_id from a unified query
             Object data = ProviderHelper.getUnifiedData(
-                    getActivity(), mSecretKeyId, KeychainContract.UserIds.USER_ID);
+                    getActivity(), mSecretKeyId, KeyRings.USER_ID);
             if(data instanceof String) {
                 String chunks[] = ((String) data).split(" <", 2);
                 uid = chunks[0];
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java
index ecd742896..b688dec51 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java
@@ -266,9 +266,6 @@ public class KeyListFragment extends Fragment
     static final int INDEX_IS_REVOKED = 3;
     static final int INDEX_HAS_SECRET = 4;
 
-    // show secret before public key, sort by user id otherwise
-    static final String SORT_ORDER = KeyRings.HAS_SECRET + " DESC, " + UserIds.USER_ID + " ASC";
-
     @Override
     public Loader onCreateLoader(int id, Bundle args) {
         // This is called when a new Loader needs to be created. This
@@ -282,7 +279,7 @@ public class KeyListFragment extends Fragment
         }
         // Now create and return a CursorLoader that will take care of
         // creating a Cursor for the data being displayed.
-        return new CursorLoader(getActivity(), baseUri, PROJECTION, where, whereArgs, SORT_ORDER);
+        return new CursorLoader(getActivity(), baseUri, PROJECTION, where, whereArgs, null);
     }
 
     @Override
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java
index b60e75fa9..5760f7d8c 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java
@@ -173,7 +173,9 @@ public class ViewKeyActivity extends ActionBarActivity {
     private void shareKey(Uri dataUri, boolean fingerprintOnly) {
         String content;
         if (fingerprintOnly) {
-            Object blob = ProviderHelper.getUnifiedData(this, dataUri, KeychainContract.Keys.FINGERPRINT);
+            Object blob = ProviderHelper.getGenericData(
+                    this, KeychainContract.KeyRings.buildUnifiedKeyRingUri(dataUri),
+                    KeychainContract.Keys.FINGERPRINT);
             if(blob instanceof byte[]) {
                 String fingerprint = PgpKeyHelper.convertFingerprintToHex((byte[]) blob);
                 content = Constants.FINGERPRINT_SCHEME + ":" + fingerprint;
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/PassphraseDialogFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/PassphraseDialogFragment.java
index b8db470b4..05b571362 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/PassphraseDialogFragment.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/PassphraseDialogFragment.java
@@ -116,7 +116,7 @@ public class PassphraseDialogFragment extends DialogFragment implements OnEditor
             secretKey = null;
             alert.setMessage(R.string.passphrase_for_symmetric_encryption);
         } else {
-            secretKey = ProviderHelper.getPGPSecretKeyByKeyId(activity, secretKeyId);
+            secretKey = ProviderHelper.getPGPSecretKeyRing(activity, secretKeyId).getSecretKey();
 
             if (secretKey == null) {
                 alert.setTitle(R.string.title_key_not_found);
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareQrCodeDialogFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareQrCodeDialogFragment.java
index dc9fa6235..b55645732 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareQrCodeDialogFragment.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareQrCodeDialogFragment.java
@@ -90,7 +90,9 @@ public class ShareQrCodeDialogFragment extends DialogFragment {
         if (mFingerprintOnly) {
             alert.setPositiveButton(R.string.btn_okay, null);
 
-            Object blob = ProviderHelper.getUnifiedData(getActivity(), dataUri, KeychainContract.Keys.FINGERPRINT);
+            Object blob = ProviderHelper.getGenericData(
+                    getActivity(), KeychainContract.KeyRings.buildUnifiedKeyRingUri(dataUri),
+                    KeychainContract.Keys.FINGERPRINT);
             if(!(blob instanceof byte[])) {
                 // TODO error handling?!
                 return null;
-- 
cgit v1.2.3


From d921cca91312e5888f98b178252efa2f5db103cf Mon Sep 17 00:00:00 2001
From: Vincent Breitmoser 
Date: Fri, 4 Apr 2014 01:07:09 +0200
Subject: db-overhaul: reintroduce by-mail and by-subkey queries

the only thing left to fix after the db upgrade (that I can think of
right now) are key exports
---
 .../keychain/provider/KeychainContract.java        |  19 ++--
 .../keychain/provider/KeychainProvider.java        | 117 ++++++++++++++-------
 .../keychain/remote/OpenPgpService.java            |  16 +--
 .../keychain/service/PassphraseCacheService.java   |  13 +--
 .../keychain/ui/EncryptAsymmetricFragment.java     |  22 +---
 5 files changed, 109 insertions(+), 78 deletions(-)

(limited to 'OpenPGP-Keychain/src')

diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java
index e6e106ba6..9eeb57222 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java
@@ -83,10 +83,9 @@ public class KeychainContract {
 
     public static final String PATH_UNIFIED = "unified";
 
-    public static final String PATH_BY_MASTER_KEY_ID = "master_key_id";
-    public static final String PATH_BY_KEY_ID = "key_id";
-    public static final String PATH_BY_EMAILS = "emails";
-    public static final String PATH_BY_LIKE_EMAIL = "like_email";
+    public static final String PATH_FIND = "find";
+    public static final String PATH_BY_EMAIL = "email";
+    public static final String PATH_BY_SUBKEY = "subkey";
 
     public static final String PATH_PUBLIC = "public";
     public static final String PATH_SECRET = "secret";
@@ -109,20 +108,24 @@ public class KeychainContract {
         public static Uri buildUnifiedKeyRingsUri() {
             return CONTENT_URI.buildUpon().appendPath(PATH_UNIFIED).build();
         }
-        public static Uri buildUnifiedKeyRingsByEmailUri(String email) {
-            return CONTENT_URI.buildUpon().appendPath("email:" + email).build();
-        }
 
         public static Uri buildGenericKeyRingUri(String masterKeyId) {
             return CONTENT_URI.buildUpon().appendPath(masterKeyId).build();
         }
-
         public static Uri buildUnifiedKeyRingUri(String masterKeyId) {
             return CONTENT_URI.buildUpon().appendPath(masterKeyId).appendPath(PATH_UNIFIED).build();
         }
         public static Uri buildUnifiedKeyRingUri(Uri uri) {
             return CONTENT_URI.buildUpon().appendPath(uri.getPathSegments().get(1)).appendPath(PATH_UNIFIED).build();
         }
+
+        public static Uri buildUnifiedKeyRingsFindByEmailUri(String email) {
+            return CONTENT_URI.buildUpon().appendPath(PATH_FIND).appendPath(PATH_BY_EMAIL).appendPath(email).build();
+        }
+        public static Uri buildUnifiedKeyRingsFindBySubkeyUri(String subkey) {
+            return CONTENT_URI.buildUpon().appendPath(PATH_FIND).appendPath(PATH_BY_SUBKEY).appendPath(subkey).build();
+        }
+
     }
 
     public static class KeyRingData implements KeyRingsColumns, BaseColumns {
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java
index 8b1ee4886..a14b5b3de 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java
@@ -57,7 +57,10 @@ public class KeychainProvider extends ContentProvider {
     private static final int API_ACCOUNTS = 304;
     private static final int API_ACCOUNTS_BY_ACCOUNT_NAME = 306;
 
-    // private static final int DATA_STREAM = 401;
+    private static final int KEY_RINGS_FIND_BY_EMAIL = 400;
+    private static final int KEY_RINGS_FIND_BY_SUBKEY = 401;
+
+    // private static final int DATA_STREAM = 501;
 
     protected UriMatcher mUriMatcher;
 
@@ -85,6 +88,20 @@ public class KeychainProvider extends ContentProvider {
                 + "/" + KeychainContract.PATH_PUBLIC,
                 KEY_RINGS_PUBLIC);
 
+        /**
+         * find by criteria other than master key id
+         *
+         * key_rings/find/email/_
+         * key_rings/find/subkey/_
+         *
+         */
+        matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/"
+                + KeychainContract.PATH_FIND + "/" + KeychainContract.PATH_BY_EMAIL + "/*",
+                KEY_RINGS_FIND_BY_EMAIL);
+        matcher.addURI(authority, KeychainContract.BASE_KEY_RINGS + "/"
+                + KeychainContract.PATH_FIND + "/" + KeychainContract.PATH_BY_SUBKEY + "/*",
+                KEY_RINGS_FIND_BY_SUBKEY);
+
         /**
          * list key_ring specifics
          *
@@ -200,7 +217,6 @@ public class KeychainProvider extends ContentProvider {
         Log.v(Constants.TAG, "query(uri=" + uri + ", proj=" + Arrays.toString(projection) + ")");
 
         SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
-        SQLiteDatabase db = mKeychainDatabase.getReadableDatabase();
 
         int match = mUriMatcher.match(uri);
 
@@ -209,7 +225,9 @@ public class KeychainProvider extends ContentProvider {
 
         switch (match) {
             case KEY_RING_UNIFIED:
-            case KEY_RINGS_UNIFIED: {
+            case KEY_RINGS_UNIFIED:
+            case KEY_RINGS_FIND_BY_EMAIL:
+            case KEY_RINGS_FIND_BY_SUBKEY: {
                 HashMap projectionMap = new HashMap();
                 projectionMap.put(KeyRings._ID, Tables.KEYS + ".oid AS _id");
                 projectionMap.put(KeyRings.MASTER_KEY_ID, Tables.KEYS + "." + Keys.MASTER_KEY_ID);
@@ -242,13 +260,64 @@ public class KeychainProvider extends ContentProvider {
                     );
                 qb.appendWhere(Tables.KEYS + "." + Keys.RANK + " = 0");
 
-                if(match == KEY_RING_UNIFIED) {
-                    qb.appendWhere(" AND " + Tables.KEYS + "." + Keys.MASTER_KEY_ID + " = ");
-                    qb.appendWhereEscapeString(uri.getPathSegments().get(1));
-                } else if (TextUtils.isEmpty(sortOrder)) {
+                switch(match) {
+                    case KEY_RING_UNIFIED: {
+                        qb.appendWhere(" AND " + Tables.KEYS + "." + Keys.MASTER_KEY_ID + " = ");
+                        qb.appendWhereEscapeString(uri.getPathSegments().get(1));
+                        break;
+                    }
+                    case KEY_RINGS_FIND_BY_SUBKEY: {
+                        try {
+                            String subkey = Long.valueOf(uri.getLastPathSegment()).toString();
+                            qb.appendWhere(" AND EXISTS ("
+                                    + " SELECT 1 FROM " + Tables.KEYS + " AS tmp"
+                                    + " WHERE tmp." + UserIds.MASTER_KEY_ID
+                                    + " = " + Tables.KEYS + "." + Keys.MASTER_KEY_ID
+                                    + " AND tmp." + Keys.KEY_ID + " = " + subkey + ""
+                                    + ")");
+                        } catch(NumberFormatException e) {
+                            Log.e(Constants.TAG, "Malformed find by subkey query!", e);
+                            qb.appendWhere(" AND 0");
+                        }
+                        break;
+                    }
+                    case KEY_RINGS_FIND_BY_EMAIL: {
+                        String chunks[] = uri.getLastPathSegment().split(" *, *");
+                        boolean gotCondition = false;
+                        String emailWhere = "";
+                        // JAVA ♥
+                        for (int i = 0; i < chunks.length; ++i) {
+                            if (chunks[i].length() == 0) {
+                                continue;
+                            }
+                            if (i != 0) {
+                                emailWhere += " OR ";
+                            }
+                            emailWhere += "tmp." + UserIds.USER_ID + " LIKE ";
+                            // match '*', so it has to be at the *end* of the user id
+                            emailWhere += DatabaseUtils.sqlEscapeString("%<" + chunks[i] + ">");
+                            gotCondition = true;
+                        }
+                        if(gotCondition) {
+                            qb.appendWhere(" AND EXISTS ("
+                                + " SELECT 1 FROM " + Tables.USER_IDS + " AS tmp"
+                                    + " WHERE tmp." + UserIds.MASTER_KEY_ID
+                                            + " = " + Tables.KEYS + "." + Keys.MASTER_KEY_ID
+                                        + " AND (" + emailWhere + ")"
+                                + ")");
+                        } else {
+                            // TODO better way to do this?
+                            Log.e(Constants.TAG, "Malformed find by email query!");
+                            qb.appendWhere(" AND 0");
+                        }
+                        break;
+                    }
+                }
+
+                if (TextUtils.isEmpty(sortOrder)) {
                     sortOrder =
-                            Tables.KEY_RINGS_SECRET + "." + KeyRings.MASTER_KEY_ID + " IS NULL DESC"
-                            + Tables.USER_IDS + "." + UserIds.USER_ID + " ASC";
+                            Tables.KEY_RINGS_SECRET + "." + KeyRings.MASTER_KEY_ID + " IS NULL ASC, "
+                                    + Tables.USER_IDS + "." + UserIds.USER_ID + " ASC";
                 }
 
                 // uri to watch is all /key_rings/
@@ -256,33 +325,6 @@ public class KeychainProvider extends ContentProvider {
 
                 break;
             }
-            /*case SECRET_KEY_RING_BY_EMAILS:
-            case PUBLIC_KEY_RING_BY_EMAILS:
-                qb = buildKeyRingQuery(qb, match);
-
-                String emails = uri.getLastPathSegment();
-                String chunks[] = emails.split(" *, *");
-                boolean gotCondition = false;
-                String emailWhere = "";
-                for (int i = 0; i < chunks.length; ++i) {
-                    if (chunks[i].length() == 0) {
-                        continue;
-                    }
-                    if (i != 0) {
-                        emailWhere += " OR ";
-                    }
-                    emailWhere += "tmp." + UserIds.USER_ID + " LIKE ";
-                    // match '*', so it has to be at the *end* of the user id
-                    emailWhere += DatabaseUtils.sqlEscapeString("%<" + chunks[i] + ">");
-                    gotCondition = true;
-                }
-
-                if (gotCondition) {
-                    qb.appendWhere(" AND EXISTS (SELECT tmp." + Base._ID + " FROM "
-                            + Tables.USER_IDS + " AS tmp WHERE tmp." + UserIds.KEY_RING_ROW_ID
-                            + " = " + Tables.KEY_RINGS + "." + Base._ID + " AND (" + emailWhere
-                            + "))");
-                }*/
 
             case KEY_RING_KEYS: {
                 HashMap projectionMap = new HashMap();
@@ -387,7 +429,7 @@ public class KeychainProvider extends ContentProvider {
 
                 break;
             default:
-                throw new IllegalArgumentException("Unknown URI " + uri);
+                throw new IllegalArgumentException("Unknown URI " + uri + " (" + match + ")");
 
         }
 
@@ -399,6 +441,7 @@ public class KeychainProvider extends ContentProvider {
             orderBy = sortOrder;
         }
 
+        SQLiteDatabase db = mKeychainDatabase.getReadableDatabase();
         Cursor c = qb.query(db, projection, selection, selectionArgs, groupBy, having, orderBy);
 
         // Tell the cursor what uri to watch, so it knows when its source data changes
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java
index ccae6b2f2..c640bdb7c 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java
@@ -61,15 +61,15 @@ public class OpenPgpService extends RemoteService {
         ArrayList keyIds = new ArrayList();
 
         boolean missingUserIdsCheck = false;
-        boolean dublicateUserIdsCheck = false;
+        boolean duplicateUserIdsCheck = false;
         ArrayList missingUserIds = new ArrayList();
-        ArrayList dublicateUserIds = new ArrayList();
+        ArrayList duplicateUserIds = new ArrayList();
 
         for (String email : encryptionUserIds) {
-            Uri uri = KeychainContract.KeyRings.buildUnifiedKeyRingsByEmailUri(email);
+            Uri uri = KeyRings.buildUnifiedKeyRingsFindByEmailUri(email);
             Cursor cur = getContentResolver().query(uri, null, null, null, null);
             if (cur.moveToFirst()) {
-                long id = cur.getLong(cur.getColumnIndex(KeychainContract.KeyRings.MASTER_KEY_ID));
+                long id = cur.getLong(cur.getColumnIndex(KeyRings.MASTER_KEY_ID));
                 keyIds.add(id);
             } else {
                 missingUserIdsCheck = true;
@@ -77,8 +77,8 @@ public class OpenPgpService extends RemoteService {
                 Log.d(Constants.TAG, "user id missing");
             }
             if (cur.moveToNext()) {
-                dublicateUserIdsCheck = true;
-                dublicateUserIds.add(email);
+                duplicateUserIdsCheck = true;
+                duplicateUserIds.add(email);
                 Log.d(Constants.TAG, "more than one user id with the same email");
             }
         }
@@ -90,13 +90,13 @@ public class OpenPgpService extends RemoteService {
         }
 
         // allow the user to verify pub key selection
-        if (missingUserIdsCheck || dublicateUserIdsCheck) {
+        if (missingUserIdsCheck || duplicateUserIdsCheck) {
             // build PendingIntent
             Intent intent = new Intent(getBaseContext(), RemoteServiceActivity.class);
             intent.setAction(RemoteServiceActivity.ACTION_SELECT_PUB_KEYS);
             intent.putExtra(RemoteServiceActivity.EXTRA_SELECTED_MASTER_KEY_IDS, keyIdsArray);
             intent.putExtra(RemoteServiceActivity.EXTRA_MISSING_USER_IDS, missingUserIds);
-            intent.putExtra(RemoteServiceActivity.EXTRA_DUBLICATE_USER_IDS, dublicateUserIds);
+            intent.putExtra(RemoteServiceActivity.EXTRA_DUBLICATE_USER_IDS, duplicateUserIds);
             intent.putExtra(RemoteServiceActivity.EXTRA_DATA, data);
 
             PendingIntent pi = PendingIntent.getActivity(getBaseContext(), 0,
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java
index 0ec4c1239..962b304c7 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java
@@ -46,6 +46,7 @@ import org.sufficientlysecure.keychain.Constants;
 import org.sufficientlysecure.keychain.Id;
 import org.sufficientlysecure.keychain.helper.Preferences;
 import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
+import org.sufficientlysecure.keychain.provider.KeychainContract;
 import org.sufficientlysecure.keychain.provider.ProviderHelper;
 
 import java.util.Date;
@@ -170,15 +171,11 @@ public class PassphraseCacheService extends Service {
         // try to get master key id which is used as an identifier for cached passphrases
         long masterKeyId = keyId;
         if (masterKeyId != Id.key.symmetric) {
-            PGPSecretKeyRing keyRing = ProviderHelper.getPGPSecretKeyRingWithKeyId(this, keyId);
-            if (keyRing == null) {
+            masterKeyId = ProviderHelper.getMasterKeyId(this,
+                    KeychainContract.KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(Long.toString(keyId)));
+            // Failure
+            if(masterKeyId == 0)
                 return null;
-            }
-            PGPSecretKey masterKey = keyRing.getSecretKey();
-            if (masterKey == null) {
-                return null;
-            }
-            masterKeyId = masterKey.getKeyID();
         }
         Log.d(TAG, "getCachedPassphraseImpl() for masterKeyId " + masterKeyId);
 
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java
index f749a4c1c..11fe4a908 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java
@@ -160,23 +160,11 @@ public class EncryptAsymmetricFragment extends Fragment {
         if (preselectedEncryptionKeyIds != null) {
             Vector goodIds = new Vector();
             for (int i = 0; i < preselectedEncryptionKeyIds.length; ++i) {
-                // TODO: don't use bouncy castle objects!
-
-                PGPPublicKeyRing keyRing = ProviderHelper.getPGPPublicKeyRingWithKeyId(getActivity(),
-                        preselectedEncryptionKeyIds[i]);
-                PGPPublicKey masterKey;
-                if (keyRing == null) {
-                    continue;
-                }
-                masterKey = keyRing.getPublicKey();
-                if (masterKey == null) {
-                    continue;
-                }
-                Vector encryptKeys = PgpKeyHelper.getUsableEncryptKeys(keyRing);
-                if (encryptKeys.size() == 0) {
-                    continue;
-                }
-                goodIds.add(masterKey.getKeyID());
+                long id = ProviderHelper.getMasterKeyId(getActivity(),
+                        KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(Long.toString(preselectedEncryptionKeyIds[i]))
+                );
+                // TODO check for available encrypt keys... is this even relevant?
+                goodIds.add(id);
             }
             if (goodIds.size() > 0) {
                 long[] keyIds = new long[goodIds.size()];
-- 
cgit v1.2.3


From 2227705d650d1e9bf3e59202a093af129c272f04 Mon Sep 17 00:00:00 2001
From: Vincent Breitmoser 
Date: Fri, 4 Apr 2014 05:01:35 +0200
Subject: db-overhaul: fix loading indicators in KeyListActivity and
 ViewKeyActivity

---
 .../sufficientlysecure/keychain/pgp/PgpImportExport.java    |  2 +-
 .../keychain/provider/KeychainDatabase.java                 |  1 -
 .../keychain/provider/KeychainProvider.java                 | 13 +++++++++----
 .../org/sufficientlysecure/keychain/ui/KeyListFragment.java |  6 +++---
 .../org/sufficientlysecure/keychain/ui/ViewKeyActivity.java |  2 ++
 .../sufficientlysecure/keychain/ui/ViewKeyMainFragment.java |  8 ++++++++
 .../src/main/res/layout/view_key_main_fragment.xml          |  3 ++-
 7 files changed, 25 insertions(+), 10 deletions(-)

(limited to 'OpenPGP-Keychain/src')

diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java
index 49ce8d3bb..d03f3ccc2 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java
@@ -260,7 +260,6 @@ public class PgpImportExport {
                 }
 
                 if (save) {
-                    ProviderHelper.saveKeyRing(mContext, secretKeyRing);
                     // TODO: preserve certifications
                     // (http://osdir.com/ml/encryption.bouncy-castle.devel/2007-01/msg00054.html ?)
                     PGPPublicKeyRing newPubRing = null;
@@ -275,6 +274,7 @@ public class PgpImportExport {
                     if (newPubRing != null) {
                         ProviderHelper.saveKeyRing(mContext, newPubRing);
                     }
+                    ProviderHelper.saveKeyRing(mContext, secretKeyRing);
                     // TODO: remove status returns, use exceptions!
                     status = Id.return_value.ok;
                 }
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java
index e0cf6b6c5..36e2a7962 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java
@@ -124,7 +124,6 @@ public class KeychainDatabase extends SQLiteOpenHelper {
     KeychainDatabase(Context context) {
         super(context, DATABASE_NAME, null, DATABASE_VERSION);
 
-
         // make sure this is only done once, on the first instance!
         boolean iAmIt = false;
         synchronized(apg_hack) {
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java
index a14b5b3de..1dd6ab08f 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java
@@ -168,10 +168,15 @@ public class KeychainProvider extends ContentProvider {
     @Override
     public boolean onCreate() {
         mUriMatcher = buildUriMatcher();
-        mKeychainDatabase = new KeychainDatabase(getContext());
         return true;
     }
 
+    public KeychainDatabase getDb() {
+        if(mKeychainDatabase == null)
+            mKeychainDatabase = new KeychainDatabase(getContext());
+        return mKeychainDatabase;
+    }
+
     /**
      * {@inheritDoc}
      */
@@ -441,7 +446,7 @@ public class KeychainProvider extends ContentProvider {
             orderBy = sortOrder;
         }
 
-        SQLiteDatabase db = mKeychainDatabase.getReadableDatabase();
+        SQLiteDatabase db = getDb().getReadableDatabase();
         Cursor c = qb.query(db, projection, selection, selectionArgs, groupBy, having, orderBy);
 
         // Tell the cursor what uri to watch, so it knows when its source data changes
@@ -465,7 +470,7 @@ public class KeychainProvider extends ContentProvider {
     public Uri insert(Uri uri, ContentValues values) {
         Log.d(Constants.TAG, "insert(uri=" + uri + ", values=" + values.toString() + ")");
 
-        final SQLiteDatabase db = mKeychainDatabase.getWritableDatabase();
+        final SQLiteDatabase db = getDb().getWritableDatabase();
 
         Uri rowUri = null;
         Long keyId = null;
@@ -538,7 +543,7 @@ public class KeychainProvider extends ContentProvider {
     public int delete(Uri uri, String additionalSelection, String[] selectionArgs) {
         Log.v(Constants.TAG, "delete(uri=" + uri + ")");
 
-        final SQLiteDatabase db = mKeychainDatabase.getWritableDatabase();
+        final SQLiteDatabase db = getDb().getWritableDatabase();
 
         int count;
         final int match = mUriMatcher.match(uri);
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java
index b688dec51..33ccd3a23 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java
@@ -154,9 +154,6 @@ public class KeyListFragment extends Fragment
         } catch (ApiLevelTooLowException e) {
         }
 
-        // this view is made visible if no data is available
-        mStickyList.setEmptyView(getActivity().findViewById(R.id.key_list_empty));
-
         /*
          * ActionBarSherlock does not support MultiChoiceModeListener. Thus multi-selection is only
          * available for Android >= 3.0
@@ -291,6 +288,9 @@ public class KeyListFragment extends Fragment
 
         mStickyList.setAdapter(mAdapter);
 
+        // this view is made visible if no data is available
+        mStickyList.setEmptyView(getActivity().findViewById(R.id.key_list_empty));
+
         // NOTE: Not supported by StickyListHeader, but reimplemented here
         // The list should now be shown.
         if (isResumed()) {
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java
index 5760f7d8c..653114c6c 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java
@@ -28,6 +28,7 @@ import android.support.v7.app.ActionBar;
 import android.support.v7.app.ActionBarActivity;
 import android.view.Menu;
 import android.view.MenuItem;
+import android.view.Window;
 import android.widget.Toast;
 import org.sufficientlysecure.keychain.Constants;
 import org.sufficientlysecure.keychain.Id;
@@ -59,6 +60,7 @@ public class ViewKeyActivity extends ActionBarActivity {
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
+        requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
         super.onCreate(savedInstanceState);
 
         mExportHelper = new ExportHelper(this);
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java
index 616200800..ae8b6d595 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java
@@ -30,6 +30,7 @@ import android.text.format.DateFormat;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
+import android.widget.LinearLayout;
 import android.widget.ListView;
 import android.widget.TextView;
 
@@ -55,6 +56,7 @@ public class ViewKeyMainFragment extends Fragment implements
 
     public static final String ARG_DATA_URI = "uri";
 
+    private LinearLayout mContainer;
     private TextView mName;
     private TextView mEmail;
     private TextView mComment;
@@ -83,6 +85,7 @@ public class ViewKeyMainFragment extends Fragment implements
     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
         View view = inflater.inflate(R.layout.view_key_main_fragment, container, false);
 
+        mContainer = (LinearLayout) view.findViewById(R.id.container);
         mName = (TextView) view.findViewById(R.id.name);
         mEmail = (TextView) view.findViewById(R.id.email);
         mComment = (TextView) view.findViewById(R.id.comment);
@@ -121,6 +124,9 @@ public class ViewKeyMainFragment extends Fragment implements
             return;
         }
 
+        getActivity().setProgressBarIndeterminateVisibility(Boolean.TRUE);
+        mContainer.setVisibility(View.GONE);
+
         mDataUri = dataUri;
 
         Log.i(Constants.TAG, "mDataUri: " + mDataUri.toString());
@@ -319,6 +325,8 @@ public class ViewKeyMainFragment extends Fragment implements
             default:
                 break;
         }
+        getActivity().setProgressBarIndeterminateVisibility(Boolean.FALSE);
+        mContainer.setVisibility(View.VISIBLE);
     }
 
     /**
diff --git a/OpenPGP-Keychain/src/main/res/layout/view_key_main_fragment.xml b/OpenPGP-Keychain/src/main/res/layout/view_key_main_fragment.xml
index 6d2bc8874..aa48252ce 100644
--- a/OpenPGP-Keychain/src/main/res/layout/view_key_main_fragment.xml
+++ b/OpenPGP-Keychain/src/main/res/layout/view_key_main_fragment.xml
@@ -12,7 +12,8 @@
         android:descendantFocusability="beforeDescendants"
         android:orientation="vertical"
         android:paddingLeft="16dp"
-        android:paddingRight="16dp">
+        android:paddingRight="16dp"
+        android:id="@+id/container">
 
         
Date: Fri, 4 Apr 2014 11:38:59 +0200
Subject: calculate nfc packet on demand only

---
 .../keychain/ui/ViewKeyActivityJB.java             | 38 ++++++++++------------
 1 file changed, 18 insertions(+), 20 deletions(-)

(limited to 'OpenPGP-Keychain/src')

diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivityJB.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivityJB.java
index 9bbbb6c7b..6ce7d9aa8 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivityJB.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivityJB.java
@@ -50,34 +50,22 @@ public class ViewKeyActivityJB extends ViewKeyActivity implements CreateNdefMess
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-
-        initNfc(mDataUri);
     }
 
     /**
      * NFC: Initialize NFC sharing if OS and device supports it
      */
-    private void initNfc(Uri dataUri) {
+    private void initNfc() {
         // check if NFC Beam is supported (>= Android 4.1)
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
             // Check for available NFC Adapter
             mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
             if (mNfcAdapter != null) {
                 // init nfc
-
-                // get public keyring as byte array
-                long masterKeyId = ProviderHelper.getMasterKeyId(this, dataUri);
-                try {
-                    mSharedKeyringBytes = ProviderHelper.getPGPPublicKeyRing(this, masterKeyId).getEncoded();
-
-                    // Register callback to set NDEF message
-                    mNfcAdapter.setNdefPushMessageCallback(this, this);
-                    // Register callback to listen for message-sent success
-                    mNfcAdapter.setOnNdefPushCompleteCallback(this, this);
-                } catch(IOException e) {
-                    // not much trouble, but leave a note
-                    Log.e(Constants.TAG, "Error parsing keyring: ", e);
-                }
+                // Register callback to set NDEF message
+                mNfcAdapter.setNdefPushMessageCallback(this, this);
+                // Register callback to listen for message-sent success
+                mNfcAdapter.setOnNdefPushCompleteCallback(this, this);
             }
         }
     }
@@ -93,9 +81,19 @@ public class ViewKeyActivityJB extends ViewKeyActivity implements CreateNdefMess
          * guarantee that this activity starts when receiving a beamed message. For now, this code
          * uses the tag dispatch system.
          */
-        NdefMessage msg = new NdefMessage(NdefRecord.createMime(Constants.NFC_MIME,
-                mSharedKeyringBytes), NdefRecord.createApplicationRecord(Constants.PACKAGE_NAME));
-        return msg;
+        // get public keyring as byte array
+        long masterKeyId = ProviderHelper.getMasterKeyId(this, mDataUri);
+        try {
+            mSharedKeyringBytes = ProviderHelper.getPGPPublicKeyRing(this, masterKeyId).getEncoded();
+
+            NdefMessage msg = new NdefMessage(NdefRecord.createMime(Constants.NFC_MIME,
+                    mSharedKeyringBytes), NdefRecord.createApplicationRecord(Constants.PACKAGE_NAME));
+            return msg;
+        } catch(IOException e) {
+            // not much trouble, but leave a note
+            Log.e(Constants.TAG, "Error parsing keyring: ", e);
+            return null;
+        }
     }
 
     /**
-- 
cgit v1.2.3


From a9f868a5e74e2c540d0b71d69560b780c7e16a06 Mon Sep 17 00:00:00 2001
From: Vincent Breitmoser 
Date: Fri, 4 Apr 2014 11:39:23 +0200
Subject: db-overhaul: different hack for type info (api level problem inside)

---
 .../keychain/provider/ProviderHelper.java          | 24 ++++++----------------
 1 file changed, 6 insertions(+), 18 deletions(-)

(limited to 'OpenPGP-Keychain/src')

diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
index a81368988..6a12184fe 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
@@ -69,26 +69,14 @@ public class ProviderHelper {
 
         HashMap result = new HashMap(proj.length);
         if (cursor != null && cursor.moveToFirst()) {
-            // this is a HACK because we don't have Cursor.getType (which is api level 11)
-            CursorWindow cursorWindow;
-            if(cursor instanceof CursorWrapper) {
-                cursorWindow = ((SQLiteCursor) ((CursorWrapper) cursor).getWrappedCursor()).getWindow();
-            } else {
-                cursorWindow = ((SQLiteCursor) cursor).getWindow();
-            }
-
             int pos = 0;
             for(String p : proj) {
-                if (cursorWindow.isNull(0, pos)) {
-                    result.put(p, cursor.isNull(pos));
-                } else if (cursorWindow.isLong(0, pos)) {
-                    result.put(p, cursor.getLong(pos));
-                } else if (cursorWindow.isFloat(0, pos)) {
-                    result.put(p, cursor.getFloat(pos));
-                } else if (cursorWindow.isString(0, pos)) {
-                    result.put(p, cursor.getString(pos));
-                } else if (cursorWindow.isBlob(0, pos)) {
-                    result.put(p, cursor.getBlob(pos));
+                switch(cursor.getType(pos)) {
+                    case Cursor.FIELD_TYPE_NULL: result.put(p, cursor.isNull(pos)); break;
+                    case Cursor.FIELD_TYPE_INTEGER: result.put(p, cursor.getLong(pos)); break;
+                    case Cursor.FIELD_TYPE_FLOAT: result.put(p, cursor.getFloat(pos)); break;
+                    case Cursor.FIELD_TYPE_STRING: result.put(p, cursor.getString(pos)); break;
+                    case Cursor.FIELD_TYPE_BLOB: result.put(p, cursor.getBlob(pos)); break;
                 }
                 pos += 1;
             }
-- 
cgit v1.2.3


From 085ce11d9cb7905d69914052fb86576805db8f01 Mon Sep 17 00:00:00 2001
From: Vincent Breitmoser 
Date: Fri, 4 Apr 2014 11:39:34 +0200
Subject: db-overhaul: workaround api level 11

---
 .../keychain/provider/ProviderHelper.java          | 38 +++++++++++++---------
 .../keychain/ui/EncryptAsymmetricFragment.java     |  8 ++---
 .../keychain/ui/ViewKeyActivity.java               | 14 ++++----
 .../ui/dialog/DeleteKeyDialogFragment.java         |  2 +-
 .../ui/dialog/ShareQrCodeDialogFragment.java       | 12 +++----
 5 files changed, 42 insertions(+), 32 deletions(-)

(limited to 'OpenPGP-Keychain/src')

diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
index 6a12184fe..581ddb378 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
@@ -61,22 +61,30 @@ import java.util.Set;
 
 public class ProviderHelper {
 
-    public static Object getGenericData(Context context, Uri uri, String column) {
-        return getGenericData(context, uri, new String[] { column }).get(column);
+    // If we ever switch to api level 11, we can ditch this whole mess!
+    public static final int FIELD_TYPE_NULL = 1;
+    // this is called integer to stay coherent with the constants in Cursor (api level 11)
+    public static final int FIELD_TYPE_INTEGER = 2;
+    public static final int FIELD_TYPE_FLOAT = 3;
+    public static final int FIELD_TYPE_STRING = 4;
+    public static final int FIELD_TYPE_BLOB = 5;
+
+    public static Object getGenericData(Context context, Uri uri, String column, int type) {
+        return getGenericData(context, uri, new String[] { column }, new int[] { type }).get(column);
     }
-    public static HashMap getGenericData(Context context, Uri uri, String[] proj) {
+    public static HashMap getGenericData(Context context, Uri uri, String[] proj, int[] types) {
         Cursor cursor = context.getContentResolver().query(uri, proj, null, null, null);
 
         HashMap result = new HashMap(proj.length);
         if (cursor != null && cursor.moveToFirst()) {
             int pos = 0;
             for(String p : proj) {
-                switch(cursor.getType(pos)) {
-                    case Cursor.FIELD_TYPE_NULL: result.put(p, cursor.isNull(pos)); break;
-                    case Cursor.FIELD_TYPE_INTEGER: result.put(p, cursor.getLong(pos)); break;
-                    case Cursor.FIELD_TYPE_FLOAT: result.put(p, cursor.getFloat(pos)); break;
-                    case Cursor.FIELD_TYPE_STRING: result.put(p, cursor.getString(pos)); break;
-                    case Cursor.FIELD_TYPE_BLOB: result.put(p, cursor.getBlob(pos)); break;
+                switch(types[pos]) {
+                    case FIELD_TYPE_NULL: result.put(p, cursor.isNull(pos)); break;
+                    case FIELD_TYPE_INTEGER: result.put(p, cursor.getLong(pos)); break;
+                    case FIELD_TYPE_FLOAT: result.put(p, cursor.getFloat(pos)); break;
+                    case FIELD_TYPE_STRING: result.put(p, cursor.getString(pos)); break;
+                    case FIELD_TYPE_BLOB: result.put(p, cursor.getBlob(pos)); break;
                 }
                 pos += 1;
             }
@@ -89,11 +97,11 @@ public class ProviderHelper {
         return result;
     }
 
-    public static Object getUnifiedData(Context context, long masterKeyId, String column) {
-        return getUnifiedData(context, masterKeyId, new String[] { column }).get(column);
+    public static Object getUnifiedData(Context context, long masterKeyId, String column, int type) {
+        return getUnifiedData(context, masterKeyId, new String[] { column }, new int[] { type }).get(column);
     }
-    public static HashMap getUnifiedData(Context context, long masterKeyId, String[] proj) {
-        return getGenericData(context, KeyRings.buildUnifiedKeyRingUri(Long.toString(masterKeyId)), proj);
+    public static HashMap getUnifiedData(Context context, long masterKeyId, String[] proj, int[] types) {
+        return getGenericData(context, KeyRings.buildUnifiedKeyRingUri(Long.toString(masterKeyId)), proj, types);
     }
 
     /** Find the master key id related to a given query. The id will either be extracted from the
@@ -108,8 +116,8 @@ public class ProviderHelper {
             // didn't work? oh well.
             Log.d(Constants.TAG, "Couldn't get masterKeyId from URI, querying...");
         }
-        Object data = getGenericData(context, queryUri, KeyRings.MASTER_KEY_ID);
-        if(data instanceof Long)
+        Object data = getGenericData(context, queryUri, KeyRings.MASTER_KEY_ID, FIELD_TYPE_INTEGER);
+        if(data != null)
             return (Long) data;
         // TODO better error handling?
         return 0L;
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java
index 67d59ab7d..6e84211cc 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java
@@ -193,10 +193,10 @@ public class EncryptAsymmetricFragment extends Fragment {
             String uid = getResources().getString(R.string.user_id_no_name);
             String uidExtra = "";
             // See if we can get a user_id from a unified query
-            Object data = ProviderHelper.getUnifiedData(
-                    getActivity(), mSecretKeyId, KeyRings.USER_ID);
-            if(data instanceof String) {
-                String chunks[] = ((String) data).split(" <", 2);
+            String user_id = (String) ProviderHelper.getUnifiedData(
+                    getActivity(), mSecretKeyId, KeyRings.USER_ID, ProviderHelper.FIELD_TYPE_STRING);
+            if(user_id != null) {
+                String chunks[] = user_id.split(" <", 2);
                 uid = chunks[0];
                 if (chunks.length > 1) {
                     uidExtra = "<" + chunks[1];
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java
index d09f85c47..af1fcfe52 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java
@@ -158,8 +158,10 @@ public class ViewKeyActivity extends ActionBarActivity {
     }
 
     private void updateFromKeyserver(Uri dataUri) {
-        byte[] fingerprintBlob = ProviderHelper.getFingerprint(this, dataUri);
-        String fingerprint = PgpKeyHelper.convertFingerprintToHex(fingerprintBlob);
+        byte[] blob = (byte[]) ProviderHelper.getGenericData(
+                this, KeychainContract.KeyRings.buildUnifiedKeyRingUri(dataUri),
+                KeychainContract.Keys.FINGERPRINT, ProviderHelper.FIELD_TYPE_BLOB);
+        String fingerprint = PgpKeyHelper.convertFingerprintToHex(blob);
 
         Intent queryIntent = new Intent(this, ImportKeysActivity.class);
         queryIntent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN);
@@ -171,11 +173,11 @@ public class ViewKeyActivity extends ActionBarActivity {
     private void shareKey(Uri dataUri, boolean fingerprintOnly) {
         String content;
         if (fingerprintOnly) {
-            Object blob = ProviderHelper.getGenericData(
+            byte[] data = (byte[]) ProviderHelper.getGenericData(
                     this, KeychainContract.KeyRings.buildUnifiedKeyRingUri(dataUri),
-                    KeychainContract.Keys.FINGERPRINT);
-            if(blob instanceof byte[]) {
-                String fingerprint = PgpKeyHelper.convertFingerprintToHex((byte[]) blob);
+                    KeychainContract.Keys.FINGERPRINT, ProviderHelper.FIELD_TYPE_BLOB);
+            if(data != null) {
+                String fingerprint = PgpKeyHelper.convertFingerprintToHex(data);
                 content = Constants.FINGERPRINT_SCHEME + ":" + fingerprint;
             } else {
                 Toast.makeText(getApplicationContext(), "Bad key selected!",
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java
index feaa0b4cd..36123a98b 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java
@@ -106,7 +106,7 @@ public class DeleteKeyDialogFragment extends DialogFragment {
             HashMap data = ProviderHelper.getUnifiedData(activity, masterKeyId, new String[]{
                     KeyRings.USER_ID,
                     KeyRings.HAS_SECRET
-            });
+            }, new int[] { ProviderHelper.FIELD_TYPE_STRING, ProviderHelper.FIELD_TYPE_INTEGER });
             String userId = (String) data.get(KeyRings.USER_ID);
             boolean hasSecret = ((Long) data.get(KeyRings.HAS_SECRET)) == 1;
 
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareQrCodeDialogFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareQrCodeDialogFragment.java
index b55645732..b6ff139df 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareQrCodeDialogFragment.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareQrCodeDialogFragment.java
@@ -31,7 +31,7 @@ import android.widget.TextView;
 import org.sufficientlysecure.keychain.Constants;
 import org.sufficientlysecure.keychain.R;
 import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
-import org.sufficientlysecure.keychain.provider.KeychainContract;
+import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
 import org.sufficientlysecure.keychain.provider.ProviderHelper;
 import org.sufficientlysecure.keychain.util.QrCodeUtils;
 
@@ -90,15 +90,15 @@ public class ShareQrCodeDialogFragment extends DialogFragment {
         if (mFingerprintOnly) {
             alert.setPositiveButton(R.string.btn_okay, null);
 
-            Object blob = ProviderHelper.getGenericData(
-                    getActivity(), KeychainContract.KeyRings.buildUnifiedKeyRingUri(dataUri),
-                    KeychainContract.Keys.FINGERPRINT);
-            if(!(blob instanceof byte[])) {
+            byte[] blob = (byte[]) ProviderHelper.getGenericData(
+                    getActivity(), KeyRings.buildUnifiedKeyRingUri(dataUri),
+                    KeyRings.FINGERPRINT, ProviderHelper.FIELD_TYPE_BLOB);
+            if(blob == null) {
                 // TODO error handling?!
                 return null;
             }
 
-            String fingerprint = PgpKeyHelper.convertFingerprintToHex((byte[]) blob);
+            String fingerprint = PgpKeyHelper.convertFingerprintToHex(blob);
             mText.setText(getString(R.string.share_qr_code_dialog_fingerprint_text) + " " + fingerprint);
             content = Constants.FINGERPRINT_SCHEME + ":" + fingerprint;
             setQrCode(content);
-- 
cgit v1.2.3


From 958eba1c95d1d25c51e8891ff5f2b8d49735e64d Mon Sep 17 00:00:00 2001
From: Vincent Breitmoser 
Date: Fri, 4 Apr 2014 13:58:12 +0200
Subject: db-overhaul: fix DecryptAndVerify with and without known keys

---
 .../keychain/pgp/PgpDecryptVerify.java             | 110 +++++++++++----------
 1 file changed, 59 insertions(+), 51 deletions(-)

(limited to 'OpenPGP-Keychain/src')

diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java
index 4b0a07d9b..8a0bf99d7 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java
@@ -53,6 +53,7 @@ import org.spongycastle.openpgp.operator.jcajce.JcePublicKeyDataDecryptorFactory
 import org.sufficientlysecure.keychain.Constants;
 import org.sufficientlysecure.keychain.R;
 import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
+import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
 import org.sufficientlysecure.keychain.provider.ProviderHelper;
 import org.sufficientlysecure.keychain.service.PassphraseCacheService;
 import org.sufficientlysecure.keychain.util.InputData;
@@ -66,6 +67,7 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.security.SignatureException;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Set;
 
@@ -232,47 +234,51 @@ public class PgpDecryptVerify {
                 updateProgress(R.string.progress_finding_key, currentProgress, 100);
 
                 PGPPublicKeyEncryptedData encData = (PGPPublicKeyEncryptedData) obj;
-                secretKey = ProviderHelper.getPGPSecretKeyRing(mContext, encData.getKeyID()).getSecretKey();
-                if (secretKey != null) {
-                    // secret key exists in database
-
-                    // allow only a specific key for decryption?
-                    if (mAllowedKeyIds != null) {
-                        // TODO: improve this code! get master key directly!
-                        PGPSecretKeyRing secretKeyRing =
-                                ProviderHelper.getPGPSecretKeyRingWithKeyId(mContext, encData.getKeyID());
-                        long masterKeyId = secretKeyRing.getSecretKey().getKeyID();
-                        Log.d(Constants.TAG, "encData.getKeyID():" + encData.getKeyID());
-                        Log.d(Constants.TAG, "allowedKeyIds: " + mAllowedKeyIds);
-                        Log.d(Constants.TAG, "masterKeyId: " + masterKeyId);
-
-                        if (!mAllowedKeyIds.contains(masterKeyId)) {
-                            throw new PgpGeneralException(
-                                    mContext.getString(R.string.error_no_secret_key_found));
-                        }
+                long masterKeyId = ProviderHelper.getMasterKeyId(mContext,
+                        KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(Long.toString(encData.getKeyID()))
+                );
+                PGPSecretKeyRing secretKeyRing = ProviderHelper.getPGPSecretKeyRing(mContext, masterKeyId);
+                if (secretKeyRing == null) {
+                    throw new PgpGeneralException(mContext.getString(R.string.error_no_secret_key_found));
+                }
+                secretKey = secretKeyRing.getSecretKey(encData.getKeyID());
+                if (secretKey == null) {
+                    throw new PgpGeneralException(mContext.getString(R.string.error_no_secret_key_found));
+                }
+                // secret key exists in database
+
+                // allow only a specific key for decryption?
+                if (mAllowedKeyIds != null) {
+                    Log.d(Constants.TAG, "encData.getKeyID():" + encData.getKeyID());
+                    Log.d(Constants.TAG, "allowedKeyIds: " + mAllowedKeyIds);
+                    Log.d(Constants.TAG, "masterKeyId: " + masterKeyId);
+
+                    if (!mAllowedKeyIds.contains(masterKeyId)) {
+                        throw new PgpGeneralException(
+                                mContext.getString(R.string.error_no_secret_key_found));
                     }
+                }
 
-                    encryptedDataAsymmetric = encData;
+                encryptedDataAsymmetric = encData;
 
-                    // if no passphrase was explicitly set try to get it from the cache service
+                // if no passphrase was explicitly set try to get it from the cache service
+                if (mPassphrase == null) {
+                    // returns "" if key has no passphrase
+                    mPassphrase =
+                            PassphraseCacheService.getCachedPassphrase(mContext, masterKeyId);
+
+                    // if passphrase was not cached, return here
+                    // indicating that a passphrase is missing!
                     if (mPassphrase == null) {
-                        // returns "" if key has no passphrase
-                        mPassphrase =
-                                PassphraseCacheService.getCachedPassphrase(mContext, encData.getKeyID());
-
-                        // if passphrase was not cached, return here
-                        // indicating that a passphrase is missing!
-                        if (mPassphrase == null) {
-                            returnData.setKeyIdPassphraseNeeded(encData.getKeyID());
-                            returnData.setStatus(PgpDecryptVerifyResult.KEY_PASSHRASE_NEEDED);
-                            return returnData;
-                        }
+                        returnData.setKeyIdPassphraseNeeded(masterKeyId);
+                        returnData.setStatus(PgpDecryptVerifyResult.KEY_PASSHRASE_NEEDED);
+                        return returnData;
                     }
-
-                    // break out of while, only get first object here
-                    // TODO???: There could be more pgp objects, which are not decrypted!
-                    break;
                 }
+
+                // break out of while, only get first object here
+                // TODO???: There could be more pgp objects, which are not decrypted!
+                break;
             } else if (mAllowSymmetricDecryption && obj instanceof PGPPBEEncryptedData) {
                 symmetricPacketFound = true;
 
@@ -545,25 +551,27 @@ public class PgpDecryptVerify {
         long signatureKeyId = 0;
         PGPPublicKey signatureKey = null;
         for (int i = 0; i < sigList.size(); ++i) {
-            signature = sigList.get(i);
-            signatureKey = ProviderHelper.getPGPPublicKeyRing(mContext, signature.getKeyID()).getPublicKey();
-            if (signatureKeyId == 0) {
-                signatureKeyId = signature.getKeyID();
-            }
 
-            if (signatureKey == null) {
+            signature = sigList.get(i);
+            signatureKeyId = signature.getKeyID();
+
+            // find data about this subkey
+            HashMap data = ProviderHelper.getGenericData(mContext,
+                    KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(Long.toString(signature.getKeyID())),
+                    new String[] { KeyRings.MASTER_KEY_ID, KeyRings.USER_ID },
+                    new int[] { ProviderHelper.FIELD_TYPE_INTEGER, ProviderHelper.FIELD_TYPE_STRING });
+            // any luck? otherwise, try next.
+            if(data.get(KeyRings.MASTER_KEY_ID) == null) {
                 signature = null;
-            } else {
-                signatureKeyId = signature.getKeyID();
-                String userId = null;
-                PGPPublicKeyRing signKeyRing = ProviderHelper.getPGPPublicKeyRingWithKeyId(mContext,
-                        signatureKeyId);
-                if (signKeyRing != null) {
-                    userId = PgpKeyHelper.getMainUserId(signKeyRing.getPublicKey());
-                }
-                signatureResult.setUserId(userId);
-                break;
+                // do NOT reset signatureKeyId, that one is shown when no known one is found!
+                continue;
             }
+
+            // this one can't fail now (yay database constraints)
+            signatureKey = ProviderHelper.getPGPPublicKeyRing(mContext, (Long) data.get(KeyRings.MASTER_KEY_ID)).getPublicKey();
+            signatureResult.setUserId((String) data.get(KeyRings.USER_ID));
+
+            break;
         }
 
         signatureResult.setKeyId(signatureKeyId);
-- 
cgit v1.2.3


From 53e8afaee035c6421c9b4efefea2d6171c6183b8 Mon Sep 17 00:00:00 2001
From: Vincent Breitmoser 
Date: Fri, 4 Apr 2014 14:37:07 +0200
Subject: ViewKeyMainFragment cleanup (don't use inline queries!)

---
 .../keychain/ui/ViewKeyMainFragment.java           | 173 +++++++++------------
 1 file changed, 77 insertions(+), 96 deletions(-)

(limited to 'OpenPGP-Keychain/src')

diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java
index ae8b6d595..5f30848f8 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java
@@ -73,6 +73,7 @@ public class ViewKeyMainFragment extends Fragment implements
     private ListView mUserIds;
     private ListView mKeys;
 
+    private static final int LOADER_ID_UNIFIED = 0;
     private static final int LOADER_ID_USER_IDS = 1;
     private static final int LOADER_ID_KEYS = 2;
 
@@ -131,60 +132,17 @@ public class ViewKeyMainFragment extends Fragment implements
 
         Log.i(Constants.TAG, "mDataUri: " + mDataUri.toString());
 
-        { // label whether secret key is available, and edit button if it is
-            final long masterKeyId = ProviderHelper.getMasterKeyId(getActivity(), mDataUri);
-            // TODO do this some other way...
-            if (ProviderHelper.hasSecretKeyByMasterKeyId(getActivity(), masterKeyId)) {
-                // set this attribute. this is a LITTLE unclean, but we have the info available
-                // right here, so why not.
-                mSecretKey.setTextColor(getResources().getColor(R.color.emphasis));
-                mSecretKey.setText(R.string.secret_key_yes);
-
-                // certify button
-                // TODO this button MIGHT be useful if the user wants to
-                // certify a private key with another...
-                // mActionCertify.setVisibility(View.GONE);
-
-                // edit button
-                mActionEdit.setVisibility(View.VISIBLE);
-                mActionEdit.setOnClickListener(new View.OnClickListener() {
-                    public void onClick(View view) {
-                        Intent editIntent = new Intent(getActivity(), EditKeyActivity.class);
-                        editIntent.setData(
-                                KeyRingData.buildSecretKeyRingUri(
-                                        Long.toString(masterKeyId)));
-                        editIntent.setAction(EditKeyActivity.ACTION_EDIT_KEY);
-                        startActivityForResult(editIntent, 0);
-                    }
-                });
-            } else {
-                mSecretKey.setTextColor(Color.BLACK);
-                mSecretKey.setText(getResources().getString(R.string.secret_key_no));
-
-                // certify button
-                mActionCertify.setVisibility(View.VISIBLE);
-                // edit button
-                mActionEdit.setVisibility(View.GONE);
-            }
-
-            // TODO see todo note above, doing this here for now
-            mActionCertify.setOnClickListener(new View.OnClickListener() {
-                public void onClick(View view) {
-                    certifyKey(KeyRings.buildGenericKeyRingUri(
-                            Long.toString(masterKeyId)
-                    ));
-                }
-            });
-
-        }
-
         mActionEncrypt.setOnClickListener(new View.OnClickListener() {
-
             @Override
             public void onClick(View v) {
                 encryptToContact(mDataUri);
             }
         });
+        mActionCertify.setOnClickListener(new View.OnClickListener() {
+            public void onClick(View view) {
+                certifyKey(mDataUri);
+            }
+        });
 
         mUserIdsAdapter = new ViewKeyUserIdsAdapter(getActivity(), null, 0);
         mUserIds.setAdapter(mUserIdsAdapter);
@@ -194,49 +152,50 @@ public class ViewKeyMainFragment extends Fragment implements
 
         // Prepare the loaders. Either re-connect with an existing ones,
         // or start new ones.
+        getActivity().getSupportLoaderManager().initLoader(LOADER_ID_UNIFIED, null, this);
         getActivity().getSupportLoaderManager().initLoader(LOADER_ID_USER_IDS, null, this);
         getActivity().getSupportLoaderManager().initLoader(LOADER_ID_KEYS, null, this);
     }
 
-    static final String[] USER_IDS_PROJECTION =
-            new String[] {
-                    UserIds._ID,
-                    UserIds.USER_ID,
-                    UserIds.RANK,
-            };
-    static final int INDEX_UID_UID = 1;
+    static final String[] UNIFIED_PROJECTION = new String[] {
+        KeyRings._ID, KeyRings.MASTER_KEY_ID, KeyRings.HAS_SECRET,
+            KeyRings.USER_ID, KeyRings.FINGERPRINT,
+            KeyRings.ALGORITHM, KeyRings.KEY_SIZE, KeyRings.CREATION, KeyRings.EXPIRY,
+
+    };
+    static final int INDEX_UNIFIED_MKI = 1;
+    static final int INDEX_UNIFIED_HAS_SECRET = 2;
+    static final int INDEX_UNIFIED_UID = 3;
+    static final int INDEX_UNIFIED_FINGERPRINT = 4;
+    static final int INDEX_UNIFIED_ALGORITHM = 5;
+    static final int INDEX_UNIFIED_KEY_SIZE = 6;
+    static final int INDEX_UNIFIED_CREATION = 7;
+    static final int INDEX_UNIFIED_EXPIRY = 8;
+
+    static final String[] USER_IDS_PROJECTION = new String[] {
+        UserIds._ID, UserIds.USER_ID, UserIds.RANK,
+    };
 
     static final String[] KEYS_PROJECTION = new String[] {
             Keys._ID,
-            Keys.KEY_ID, Keys.RANK,
-            Keys.ALGORITHM, Keys.KEY_SIZE,
-            Keys.CAN_CERTIFY, Keys.CAN_ENCRYPT,
-            Keys.CAN_SIGN, Keys.IS_REVOKED,
-            Keys.CREATION, Keys.EXPIRY,
-            Keys.FINGERPRINT
+            Keys.KEY_ID, Keys.RANK, Keys.ALGORITHM, Keys.KEY_SIZE,
+            Keys.CAN_CERTIFY, Keys.CAN_ENCRYPT, Keys.CAN_SIGN, Keys.IS_REVOKED,
+            Keys.CREATION, Keys.EXPIRY, Keys.FINGERPRINT
     };
-    static final int KEYS_INDEX_KEY_ID = 1;
-    static final int KEYS_INDEX_ALGORITHM = 3;
-    static final int KEYS_INDEX_KEY_SIZE = 4;
     static final int KEYS_INDEX_CAN_ENCRYPT = 6;
-    static final int KEYS_INDEX_CREATION = 9;
-    static final int KEYS_INDEX_EXPIRY = 10;
-    static final int KEYS_INDEX_FINGERPRINT = 11;
 
     public Loader onCreateLoader(int id, Bundle args) {
         switch (id) {
+            case LOADER_ID_UNIFIED: {
+                Uri baseUri = KeyRings.buildUnifiedKeyRingUri(mDataUri);
+                return new CursorLoader(getActivity(), baseUri, UNIFIED_PROJECTION, null, null, null);
+            }
             case LOADER_ID_USER_IDS: {
                 Uri baseUri = UserIds.buildUserIdsUri(mDataUri);
-
-                // Now create and return a CursorLoader that will take care of
-                // creating a Cursor for the data being displayed.
                 return new CursorLoader(getActivity(), baseUri, USER_IDS_PROJECTION, null, null, null);
             }
             case LOADER_ID_KEYS: {
                 Uri baseUri = Keys.buildKeysUri(mDataUri);
-
-                // Now create and return a CursorLoader that will take care of
-                // creating a Cursor for the data being displayed.
                 return new CursorLoader(getActivity(), baseUri, KEYS_PROJECTION, null, null, null);
             }
 
@@ -249,11 +208,10 @@ public class ViewKeyMainFragment extends Fragment implements
         // Swap the new cursor in. (The framework will take care of closing the
         // old cursor once we return.)
         switch (loader.getId()) {
-            case LOADER_ID_USER_IDS:
+            case LOADER_ID_UNIFIED: {
                 if (data.moveToFirst()) {
                     // get name, email, and comment from USER_ID
-                    String[] mainUserId = PgpKeyHelper.splitUserId(data
-                            .getString(INDEX_UID_UID));
+                    String[] mainUserId = PgpKeyHelper.splitUserId(data.getString(INDEX_UNIFIED_UID));
                     if (mainUserId[0] != null) {
                         getActivity().setTitle(mainUserId[0]);
                         mName.setText(mainUserId[0]);
@@ -263,22 +221,43 @@ public class ViewKeyMainFragment extends Fragment implements
                     }
                     mEmail.setText(mainUserId[1]);
                     mComment.setText(mainUserId[2]);
-                }
-                mUserIdsAdapter.swapCursor(data);
-                break;
-            case LOADER_ID_KEYS:
-                // the first key here is our master key
-                if (data.moveToFirst()) {
+
+                    if (data.getInt(INDEX_UNIFIED_HAS_SECRET) > 0) {
+                        // set this attribute. this is a LITTLE unclean, but we have the info available
+                        // right here, so why not.
+                        mSecretKey.setTextColor(getResources().getColor(R.color.emphasis));
+                        mSecretKey.setText(R.string.secret_key_yes);
+
+                        // edit button
+                        mActionEdit.setVisibility(View.VISIBLE);
+                        mActionEdit.setOnClickListener(new View.OnClickListener() {
+                            public void onClick(View view) {
+                                Intent editIntent = new Intent(getActivity(), EditKeyActivity.class);
+                                editIntent.setData(mDataUri);
+                                editIntent.setAction(EditKeyActivity.ACTION_EDIT_KEY);
+                                startActivityForResult(editIntent, 0);
+                            }
+                        });
+                    } else {
+                        mSecretKey.setTextColor(Color.BLACK);
+                        mSecretKey.setText(getResources().getString(R.string.secret_key_no));
+
+                        // certify button
+                        mActionCertify.setVisibility(View.VISIBLE);
+                        // edit button
+                        mActionEdit.setVisibility(View.GONE);
+                    }
+
                     // get key id from MASTER_KEY_ID
-                    long keyId = data.getLong(KEYS_INDEX_KEY_ID);
-                    String keyIdStr = PgpKeyHelper.convertKeyIdToHex(keyId);
+                    long masterKeyId = data.getLong(INDEX_UNIFIED_MKI);
+                    String keyIdStr = PgpKeyHelper.convertKeyIdToHex(masterKeyId);
                     mKeyId.setText(keyIdStr);
 
                     // get creation date from CREATION
-                    if (data.isNull(KEYS_INDEX_CREATION)) {
+                    if (data.isNull(INDEX_UNIFIED_CREATION)) {
                         mCreation.setText(R.string.none);
                     } else {
-                        Date creationDate = new Date(data.getLong(KEYS_INDEX_CREATION) * 1000);
+                        Date creationDate = new Date(data.getLong(INDEX_UNIFIED_CREATION) * 1000);
 
                         mCreation.setText(
                                 DateFormat.getDateFormat(getActivity().getApplicationContext()).format(
@@ -286,10 +265,10 @@ public class ViewKeyMainFragment extends Fragment implements
                     }
 
                     // get expiry date from EXPIRY
-                    if (data.isNull(KEYS_INDEX_EXPIRY)) {
+                    if (data.isNull(INDEX_UNIFIED_EXPIRY)) {
                         mExpiry.setText(R.string.none);
                     } else {
-                        Date expiryDate = new Date(data.getLong(KEYS_INDEX_EXPIRY) * 1000);
+                        Date expiryDate = new Date(data.getLong(INDEX_UNIFIED_EXPIRY) * 1000);
 
                         mExpiry.setText(
                                 DateFormat.getDateFormat(getActivity().getApplicationContext()).format(
@@ -297,15 +276,22 @@ public class ViewKeyMainFragment extends Fragment implements
                     }
 
                     String algorithmStr = PgpKeyHelper.getAlgorithmInfo(
-                            data.getInt(KEYS_INDEX_ALGORITHM), data.getInt(KEYS_INDEX_KEY_SIZE));
+                            data.getInt(INDEX_UNIFIED_ALGORITHM), data.getInt(INDEX_UNIFIED_KEY_SIZE));
                     mAlgorithm.setText(algorithmStr);
 
-                    byte[] fingerprintBlob = data.getBlob(KEYS_INDEX_FINGERPRINT);
+                    byte[] fingerprintBlob = data.getBlob(INDEX_UNIFIED_FINGERPRINT);
                     String fingerprint = PgpKeyHelper.convertFingerprintToHex(fingerprintBlob);
-
                     mFingerprint.setText(PgpKeyHelper.colorizeFingerprint(fingerprint));
+
+                    break;
                 }
+            }
 
+            case LOADER_ID_USER_IDS:
+                mUserIdsAdapter.swapCursor(data);
+                break;
+
+            case LOADER_ID_KEYS:
                 // hide encrypt button if no encryption key is available
                 boolean canEncrypt = false;
                 data.moveToFirst();
@@ -321,9 +307,6 @@ public class ViewKeyMainFragment extends Fragment implements
 
                 mKeysAdapter.swapCursor(data);
                 break;
-
-            default:
-                break;
         }
         getActivity().setProgressBarIndeterminateVisibility(Boolean.FALSE);
         mContainer.setVisibility(View.VISIBLE);
@@ -341,8 +324,6 @@ public class ViewKeyMainFragment extends Fragment implements
             case LOADER_ID_KEYS:
                 mKeysAdapter.swapCursor(null);
                 break;
-            default:
-                break;
         }
     }
 
-- 
cgit v1.2.3


From cf76a8553a686e1e9c8757b39b6b4e3c4b05bb0c Mon Sep 17 00:00:00 2001
From: Vincent Breitmoser 
Date: Fri, 4 Apr 2014 16:28:28 +0200
Subject: db-overhaul: fix delete key from ViewKeyActivity

---
 .../sufficientlysecure/keychain/helper/ExportHelper.java    |  7 +++----
 .../sufficientlysecure/keychain/ui/ViewKeyMainFragment.java |  7 ++++++-
 .../keychain/ui/dialog/DeleteKeyDialogFragment.java         | 13 +++----------
 3 files changed, 12 insertions(+), 15 deletions(-)

(limited to 'OpenPGP-Keychain/src')

diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/ExportHelper.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/ExportHelper.java
index 43fdc7751..3040b4e9c 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/ExportHelper.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/ExportHelper.java
@@ -30,6 +30,7 @@ import org.sufficientlysecure.keychain.Constants;
 import org.sufficientlysecure.keychain.Id;
 import org.sufficientlysecure.keychain.R;
 import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround;
+import org.sufficientlysecure.keychain.provider.ProviderHelper;
 import org.sufficientlysecure.keychain.service.KeychainIntentService;
 import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
 import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment;
@@ -48,14 +49,12 @@ public class ExportHelper {
     }
 
     public void deleteKey(Uri dataUri, Handler deleteHandler) {
-        long keyRingRowId = Long.valueOf(dataUri.getLastPathSegment());
-
         // Create a new Messenger for the communication back
         Messenger messenger = new Messenger(deleteHandler);
+        long masterKeyId = ProviderHelper.getMasterKeyId(mActivity, dataUri);
 
         DeleteKeyDialogFragment deleteKeyDialog = DeleteKeyDialogFragment.newInstance(messenger,
-                new long[]{keyRingRowId});
-
+                new long[]{ masterKeyId });
         deleteKeyDialog.show(mActivity.getSupportFragmentManager(), "deleteKeyDialog");
     }
 
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java
index 5f30848f8..3c6ae514e 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java
@@ -42,7 +42,6 @@ import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
 import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
 import org.sufficientlysecure.keychain.provider.KeychainContract.Keys;
 import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds;
-import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData;
 import org.sufficientlysecure.keychain.provider.ProviderHelper;
 import org.sufficientlysecure.keychain.ui.adapter.ViewKeyKeysAdapter;
 import org.sufficientlysecure.keychain.ui.adapter.ViewKeyUserIdsAdapter;
@@ -205,6 +204,12 @@ public class ViewKeyMainFragment extends Fragment implements
     }
 
     public void onLoadFinished(Loader loader, Cursor data) {
+        /* TODO better error handling? May cause problems when a key is deleted,
+         * because the notification triggers faster than the activity closes.
+         */
+        // Avoid NullPointerExceptions...
+        if(data.getCount() == 0)
+            return;
         // Swap the new cursor in. (The framework will take care of closing the
         // old cursor once we return.)
         switch (loader.getId()) {
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java
index 36123a98b..72ea4c013 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java
@@ -75,7 +75,6 @@ public class DeleteKeyDialogFragment extends DialogFragment {
         return frag;
     }
 
-
     @Override
     public Dialog onCreateDialog(Bundle savedInstanceState) {
 
@@ -122,7 +121,6 @@ public class DeleteKeyDialogFragment extends DialogFragment {
             mMainMessage.setText(R.string.key_deletion_confirmation_multi);
         }
 
-
         builder.setIcon(R.drawable.ic_dialog_alert_holo_light);
         builder.setPositiveButton(R.string.btn_delete, new DialogInterface.OnClickListener() {
             @Override
@@ -133,21 +131,16 @@ public class DeleteKeyDialogFragment extends DialogFragment {
                     int count = activity.getContentResolver().delete(
                             KeyRingData.buildPublicKeyRingUri(Long.toString(masterKeyId)), null, null
                         );
-                    if(count > 0)
-                    success = true;
+                    success = count > 0;
                 }
-
-                dismiss();
-
                 if (success) {
                     sendMessageToHandler(MESSAGE_OKAY, null);
                 } else {
                     sendMessageToHandler(MESSAGE_ERROR, null);
                 }
+                dismiss();
             }
-
-        }
-        );
+        });
         builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
 
             @Override
-- 
cgit v1.2.3


From d7c2488a0f08c8314706f76c22b53166309bcdf0 Mon Sep 17 00:00:00 2001
From: Vincent Breitmoser 
Date: Fri, 4 Apr 2014 18:49:45 +0200
Subject: db-overhaul: fix key export (and some export-related ui changes)

---
 .../keychain/helper/ExportHelper.java              | 19 +++----
 .../keychain/service/KeychainIntentService.java    | 58 ++++++++++------------
 .../keychain/ui/EditKeyActivity.java               |  5 +-
 .../keychain/ui/KeyListActivity.java               | 15 ++----
 .../keychain/ui/KeyListFragment.java               | 23 ++++++---
 .../keychain/ui/ViewKeyActivity.java               | 11 ++--
 .../keychain/ui/ViewKeyMainFragment.java           | 16 ++++--
 OpenPGP-Keychain/src/main/res/menu/key_list.xml    | 11 ----
 8 files changed, 77 insertions(+), 81 deletions(-)

(limited to 'OpenPGP-Keychain/src')

diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/ExportHelper.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/ExportHelper.java
index 3040b4e9c..810f22d8e 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/ExportHelper.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/helper/ExportHelper.java
@@ -61,8 +61,8 @@ public class ExportHelper {
     /**
      * Show dialog where to export keys
      */
-    public void showExportKeysDialog(final long[] masterKeyIds, final int keyType,
-                                     final String exportFilename, final String checkboxString) {
+    public void showExportKeysDialog(final long[] masterKeyIds, final String exportFilename,
+                                     final boolean showSecretCheckbox) {
         mExportFilename = exportFilename;
 
         // Message is received after file is selected
@@ -71,14 +71,9 @@ public class ExportHelper {
             public void handleMessage(Message message) {
                 if (message.what == FileDialogFragment.MESSAGE_OKAY) {
                     Bundle data = message.getData();
-                    int type = keyType;
                     mExportFilename = data.getString(FileDialogFragment.MESSAGE_DATA_FILENAME);
 
-                    if (data.getBoolean(FileDialogFragment.MESSAGE_DATA_CHECKED)) {
-                        type = Id.type.public_secret_key;
-                    }
-
-                    exportKeys(masterKeyIds, type);
+                    exportKeys(masterKeyIds, data.getBoolean(FileDialogFragment.MESSAGE_DATA_CHECKED));
                 }
             }
         };
@@ -98,9 +93,11 @@ public class ExportHelper {
                 }
 
                 String message = mActivity.getString(R.string.specify_file_to_export_to);
+                String checkMsg = showSecretCheckbox ?
+                        mActivity.getString(R.string.also_export_secret_keys) : null;
 
                 mFileDialog = FileDialogFragment.newInstance(messenger, title, message,
-                        exportFilename, checkboxString);
+                        exportFilename, checkMsg);
 
                 mFileDialog.show(mActivity.getSupportFragmentManager(), "fileDialog");
             }
@@ -110,7 +107,7 @@ public class ExportHelper {
     /**
      * Export keys
      */
-    public void exportKeys(long[] masterKeyIds, int keyType) {
+    public void exportKeys(long[] masterKeyIds, boolean exportSecret) {
         Log.d(Constants.TAG, "exportKeys started");
 
         // Send all information needed to service to export key in other thread
@@ -122,7 +119,7 @@ public class ExportHelper {
         Bundle data = new Bundle();
 
         data.putString(KeychainIntentService.EXPORT_FILENAME, mExportFilename);
-        data.putInt(KeychainIntentService.EXPORT_KEY_TYPE, keyType);
+        data.putBoolean(KeychainIntentService.EXPORT_SECRET, exportSecret);
 
         if (masterKeyIds == null) {
             data.putBoolean(KeychainIntentService.EXPORT_ALL, true);
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
index 768237c7d..1c6aa7971 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
@@ -19,6 +19,7 @@ package org.sufficientlysecure.keychain.service;
 
 import android.app.IntentService;
 import android.content.Intent;
+import android.database.Cursor;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Message;
@@ -50,6 +51,8 @@ import org.sufficientlysecure.keychain.pgp.PgpKeyOperation;
 import org.sufficientlysecure.keychain.pgp.PgpSignEncrypt;
 import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
 import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralMsgIdException;
+import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
+import org.sufficientlysecure.keychain.provider.KeychainDatabase;
 import org.sufficientlysecure.keychain.provider.ProviderHelper;
 import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry;
 import org.sufficientlysecure.keychain.util.HkpKeyServer;
@@ -147,7 +150,7 @@ public class KeychainIntentService extends IntentService
     // export key
     public static final String EXPORT_OUTPUT_STREAM = "export_output_stream";
     public static final String EXPORT_FILENAME = "export_filename";
-    public static final String EXPORT_KEY_TYPE = "export_key_type";
+    public static final String EXPORT_SECRET = "export_secret";
     public static final String EXPORT_ALL = "export_all";
     public static final String EXPORT_KEY_RING_MASTER_KEY_ID = "export_key_ring_id";
 
@@ -635,19 +638,13 @@ public class KeychainIntentService extends IntentService
         } else if (ACTION_EXPORT_KEYRING.equals(action)) {
             try {
 
-                /* Input */
-                int keyType = Id.type.public_key;
-                if (data.containsKey(EXPORT_KEY_TYPE)) {
-                    keyType = data.getInt(EXPORT_KEY_TYPE);
-                }
+                boolean exportSecret = data.getBoolean(EXPORT_SECRET, false);
                 long[] masterKeyIds = data.getLongArray(EXPORT_KEY_RING_MASTER_KEY_ID);
                 String outputFile = data.getString(EXPORT_FILENAME);
 
                 // If not exporting all keys get the masterKeyIds of the keys to export from the intent
                 boolean exportAll = data.getBoolean(EXPORT_ALL);
 
-                /* Operation */
-
                 // check if storage is ready
                 if (!FileHelper.isStorageMounted(outputFile)) {
                     throw new PgpGeneralException(getString(R.string.error_external_storage_not_ready));
@@ -655,31 +652,30 @@ public class KeychainIntentService extends IntentService
 
                 ArrayList publicMasterKeyIds = new ArrayList();
                 ArrayList secretMasterKeyIds = new ArrayList();
-                // TODO redo
-                ArrayList allPublicMasterKeyIds = null; // ProviderHelper.getPublicKeyRingsMasterKeyIds(this);
-                ArrayList allSecretMasterKeyIds = null; // ProviderHelper.getSecretKeyRingsMasterKeyIds(this);
-
-                if (exportAll) {
-                    // get all public key ring MasterKey ids
-                    if (keyType == Id.type.public_key || keyType == Id.type.public_secret_key) {
-                        publicMasterKeyIds = allPublicMasterKeyIds;
-                    }
-                    // get all secret key ring MasterKey ids
-                    if (keyType == Id.type.secret_key || keyType == Id.type.public_secret_key) {
-                        secretMasterKeyIds = allSecretMasterKeyIds;
-                    }
-                } else {
 
-                    for (long masterKeyId : masterKeyIds) {
-                        if ((keyType == Id.type.public_key || keyType == Id.type.public_secret_key)
-                                && allPublicMasterKeyIds.contains(masterKeyId)) {
-                            publicMasterKeyIds.add(masterKeyId);
-                        }
-                        if ((keyType == Id.type.secret_key || keyType == Id.type.public_secret_key)
-                                && allSecretMasterKeyIds.contains(masterKeyId)) {
-                            secretMasterKeyIds.add(masterKeyId);
-                        }
+                String selection = null;
+                if(!exportAll) {
+                    selection = KeychainDatabase.Tables.KEYS + "." + KeyRings.MASTER_KEY_ID + " IN( ";
+                    for(long l : masterKeyIds) {
+                        selection += Long.toString(l) + ",";
                     }
+                    selection = selection.substring(0, selection.length()-1) + " )";
+                }
+
+                Cursor cursor = getContentResolver().query(KeyRings.buildUnifiedKeyRingsUri(),
+                        new String[]{ KeyRings.MASTER_KEY_ID, KeyRings.HAS_SECRET },
+                        selection, null, null);
+                try {
+                    cursor.moveToFirst();
+                    do {
+                        // export public either way
+                        publicMasterKeyIds.add(cursor.getLong(0));
+                        // add secret if available (and requested)
+                        if(exportSecret && cursor.getInt(1) != 0)
+                            secretMasterKeyIds.add(cursor.getLong(0));
+                    } while(cursor.moveToNext());
+                } finally {
+                    cursor.close();
                 }
 
                 PgpImportExport pgpImportExport = new PgpImportExport(this, this, this);
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java
index e6fd59d55..167401ac5 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java
@@ -339,9 +339,8 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener
                     Toast.makeText(this, R.string.error_save_first, Toast.LENGTH_LONG).show();
                 } else {
                     long masterKeyId = ProviderHelper.getMasterKeyId(this, mDataUri);
-                long[] ids = new long[]{masterKeyId};
-                mExportHelper.showExportKeysDialog(ids, Id.type.secret_key, Constants.Path.APP_DIR_FILE_SEC,
-                        null);
+                    mExportHelper.showExportKeysDialog(
+                            new long[] { masterKeyId }, Constants.Path.APP_DIR_FILE_SEC, true);
                     return true;
                 }
                 return true;
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java
index 1f884d7e3..1bc6d4ee1 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java
@@ -23,7 +23,6 @@ import android.view.Menu;
 import android.view.MenuItem;
 
 import org.sufficientlysecure.keychain.Constants;
-import org.sufficientlysecure.keychain.Id;
 import org.sufficientlysecure.keychain.R;
 import org.sufficientlysecure.keychain.helper.ExportHelper;
 
@@ -55,26 +54,20 @@ public class KeyListActivity extends DrawerActivity {
         switch (item.getItemId()) {
             case R.id.menu_key_list_import:
                 callIntentForDrawerItem(Constants.DrawerItems.IMPORT_KEYS);
-
                 return true;
+
             case R.id.menu_key_list_create:
                 createKey();
-
                 return true;
+
             case R.id.menu_key_list_create_expert:
                 createKeyExpert();
-
                 return true;
-            case R.id.menu_key_list_export_public:
-                mExportHelper.showExportKeysDialog(null,
-                    Id.type.public_key, Constants.Path.APP_DIR_FILE_PUB, null);
 
+            case R.id.menu_key_list_export:
+                mExportHelper.showExportKeysDialog(null, Constants.Path.APP_DIR_FILE_PUB, true);
                 return true;
-            case R.id.menu_key_list_secret_export:
-                mExportHelper.showExportKeysDialog(null, Id.type.secret_key,
-                    Constants.Path.APP_DIR_FILE_SEC, null);
 
-                return true;
             default:
                 return super.onOptionsItemSelected(item);
         }
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java
index 33ccd3a23..1d8f7c8ad 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java
@@ -60,7 +60,6 @@ import org.sufficientlysecure.keychain.helper.ExportHelper;
 import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
 import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
 import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData;
-import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds;
 import org.sufficientlysecure.keychain.ui.adapter.HighlightQueryCursorAdapter;
 import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment;
 import org.sufficientlysecure.keychain.util.Log;
@@ -68,7 +67,6 @@ import se.emilsjolander.stickylistheaders.ApiLevelTooLowException;
 import se.emilsjolander.stickylistheaders.StickyListHeadersAdapter;
 import se.emilsjolander.stickylistheaders.StickyListHeadersListView;
 
-import java.util.ArrayList;
 import java.util.HashMap;
 
 /**
@@ -194,10 +192,8 @@ public class KeyListFragment extends Fragment
                         case R.id.menu_key_list_multi_export: {
                             ids = mAdapter.getCurrentSelectedMasterKeyIds();
                             ExportHelper mExportHelper = new ExportHelper((ActionBarActivity) getActivity());
-                            mExportHelper
-                                    .showExportKeysDialog(ids, Id.type.public_key,
-                                            Constants.Path.APP_DIR_FILE_PUB,
-                                            getString(R.string.also_export_secret_keys));
+                            mExportHelper.showExportKeysDialog(
+                                    ids, Constants.Path.APP_DIR_FILE_PUB, mAdapter.isAnySecretSelected());
                             break;
                         }
                         case R.id.menu_key_list_multi_select_all: {
@@ -525,6 +521,13 @@ public class KeyListFragment extends Fragment
 
         }
 
+        public boolean isSecretAvailable(int id) {
+            if (!mCursor.moveToPosition(id)) {
+                throw new IllegalStateException("couldn't move cursor to position " + id);
+            }
+
+            return mCursor.getInt(INDEX_HAS_SECRET) != 0;
+        }
         public long getMasterKeyId(int id) {
             if (!mCursor.moveToPosition(id)) {
                 throw new IllegalStateException("couldn't move cursor to position " + id);
@@ -633,6 +636,14 @@ public class KeyListFragment extends Fragment
             notifyDataSetChanged();
         }
 
+        public boolean isAnySecretSelected() {
+            for (int pos : mSelection.keySet()) {
+                if(mAdapter.isSecretAvailable(pos))
+                    return true;
+            }
+            return false;
+        }
+
         public long[] getCurrentSelectedMasterKeyIds() {
             long[] ids = new long[mSelection.size()];
             int i = 0;
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java
index af1fcfe52..7b9ba4b2d 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java
@@ -42,7 +42,6 @@ import org.sufficientlysecure.keychain.provider.ProviderHelper;
 import org.sufficientlysecure.keychain.ui.adapter.TabsAdapter;
 import org.sufficientlysecure.keychain.ui.dialog.ShareNfcDialogFragment;
 import org.sufficientlysecure.keychain.ui.dialog.ShareQrCodeDialogFragment;
-import org.sufficientlysecure.keychain.util.Log;
 
 import java.util.ArrayList;
 
@@ -120,10 +119,12 @@ public class ViewKeyActivity extends ActionBarActivity {
                 uploadToKeyserver(mDataUri);
                 return true;
             case R.id.menu_key_view_export_file:
-                long masterKeyId = Long.valueOf(mDataUri.getLastPathSegment());
-                long[] ids = new long[]{masterKeyId};
-                mExportHelper.showExportKeysDialog(ids, Id.type.public_key,
-                        Constants.Path.APP_DIR_FILE_PUB, null);
+                long masterKeyId = ProviderHelper.getMasterKeyId(this, mDataUri);
+                mExportHelper.showExportKeysDialog(
+                        new long[] { masterKeyId } , Constants.Path.APP_DIR_FILE_PUB,
+                        // TODO this doesn't work?
+                        ((ViewKeyMainFragment) mTabsAdapter.getItem(0)).isSecretAvailable()
+                );
                 return true;
             case R.id.menu_key_view_share_default_fingerprint:
                 shareKey(mDataUri, true);
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java
index 3c6ae514e..830c5fcae 100644
--- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java
+++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java
@@ -81,6 +81,9 @@ public class ViewKeyMainFragment extends Fragment implements
 
     private Uri mDataUri;
 
+    // for activity
+    private boolean mSecretAvailable = false;
+
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
         View view = inflater.inflate(R.layout.view_key_main_fragment, container, false);
@@ -227,9 +230,9 @@ public class ViewKeyMainFragment extends Fragment implements
                     mEmail.setText(mainUserId[1]);
                     mComment.setText(mainUserId[2]);
 
-                    if (data.getInt(INDEX_UNIFIED_HAS_SECRET) > 0) {
-                        // set this attribute. this is a LITTLE unclean, but we have the info available
-                        // right here, so why not.
+                    if (data.getInt(INDEX_UNIFIED_HAS_SECRET) != 0) {
+                        mSecretAvailable = true;
+
                         mSecretKey.setTextColor(getResources().getColor(R.color.emphasis));
                         mSecretKey.setText(R.string.secret_key_yes);
 
@@ -244,6 +247,8 @@ public class ViewKeyMainFragment extends Fragment implements
                             }
                         });
                     } else {
+                        mSecretAvailable = false;
+
                         mSecretKey.setTextColor(Color.BLACK);
                         mSecretKey.setText(getResources().getString(R.string.secret_key_no));
 
@@ -332,6 +337,11 @@ public class ViewKeyMainFragment extends Fragment implements
         }
     }
 
+    /** Returns true if the key current displayed is known to have a secret key. */
+    public boolean isSecretAvailable() {
+        return mSecretAvailable;
+    }
+
     private void encryptToContact(Uri dataUri) {
         // TODO preselect from uri? should be feasible without trivial query
         long keyId = ProviderHelper.getMasterKeyId(getActivity(), dataUri);
diff --git a/OpenPGP-Keychain/src/main/res/menu/key_list.xml b/OpenPGP-Keychain/src/main/res/menu/key_list.xml
index bcb2a4b99..b75f4e9a6 100644
--- a/OpenPGP-Keychain/src/main/res/menu/key_list.xml
+++ b/OpenPGP-Keychain/src/main/res/menu/key_list.xml
@@ -38,17 +38,6 @@
         app:showAsAction="ifRoom|withText"
         android:icon="@drawable/ic_action_import_export"
         android:title="@string/menu_export_keys">
-        
-            
-
-            
-        
     
 
 
-- 
cgit v1.2.3