diff options
Diffstat (limited to 'OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider')
4 files changed, 310 insertions, 376 deletions
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..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"; @@ -96,31 +95,49 @@ 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() { 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 { + 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 +152,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/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 39ea083fa..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 @@ -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; @@ -65,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; @@ -79,18 +74,36 @@ public class KeychainProvider extends ContentProvider { String authority = KeychainContract.CONTENT_AUTHORITY; /** - * select from key_ring + * list key_rings * * <pre> * key_rings/unified + * key_rings/public * </pre> */ 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); + + /** + * 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); /** - * select from key_ring + * list key_ring specifics * * <pre> * key_rings/_/unified @@ -155,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} */ @@ -204,7 +222,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); @@ -213,98 +230,126 @@ 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<String, String> projectionMap = new HashMap<String, String>(); - 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.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 '*<email>', 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 + "." + UserIdsColumns.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/ + uri = KeyRings.CONTENT_URI; + 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." + UserIdsColumns.USER_ID + " LIKE "; - // match '*<email>', 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 - + "))"); - }*/ case KEY_RING_KEYS: { HashMap<String, String> projectionMap = new HashMap<String, String>(); - 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; @@ -312,7 +357,7 @@ public class KeychainProvider extends ContentProvider { case KEY_RING_USER_IDS: { HashMap<String, String> projectionMap = new HashMap<String, String>(); - 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); @@ -320,36 +365,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<String, String> projectionMap = new HashMap<String, String>(); - 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<String, String> projectionMap = new HashMap<String, String>(); - 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; @@ -381,7 +434,7 @@ public class KeychainProvider extends ContentProvider { break; default: - throw new IllegalArgumentException("Unknown URI " + uri); + throw new IllegalArgumentException("Unknown URI " + uri + " (" + match + ")"); } @@ -393,6 +446,7 @@ public class KeychainProvider extends ContentProvider { orderBy = sortOrder; } + 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 @@ -416,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; @@ -426,23 +480,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: @@ -489,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); @@ -503,6 +557,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 +567,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 3f96a51ef..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 @@ -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; @@ -40,9 +43,9 @@ 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.provider.KeychainDatabase.Tables; import org.sufficientlysecure.keychain.remote.AccountSettings; import org.sufficientlysecure.keychain.remote.AppSettings; import org.sufficientlysecure.keychain.util.IterableIterator; @@ -52,21 +55,81 @@ 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; public class ProviderHelper { - /** - * Private helper method to get PGPKeyRing from database + // 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<String,Object> getGenericData(Context context, Uri uri, String[] proj, int[] types) { + Cursor cursor = context.getContentResolver().query(uri, proj, null, null, null); + + HashMap<String, Object> result = new HashMap<String, Object>(proj.length); + if (cursor != null && cursor.moveToFirst()) { + int pos = 0; + for(String p : proj) { + 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; + } + } + + if (cursor != null) { + cursor.close(); + } + + return result; + } + + 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<String,Object> 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 + * 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, FIELD_TYPE_INTEGER); + if(data != null) + return (Long) data; + // TODO better error handling? + return 0L; + } + 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) { @@ -81,19 +144,18 @@ public class ProviderHelper { return keyRing; } - public static PGPPublicKey getPGPPublicKeyByKeyId(Context context, long keyId) { - return getPGPPublicKeyRingWithKeyId(context, keyId).getPublicKey(keyId); - } public static PGPPublicKeyRing getPGPPublicKeyRingWithKeyId(Context context, long keyId) { - // todo do + Uri uri = KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(Long.toString(keyId)); + long masterKeyId = getMasterKeyId(context, uri); + if(masterKeyId != 0) + return getPGPPublicKeyRing(context, masterKeyId); return null; } - - public static PGPSecretKey getPGPSecretKeyByKeyId(Context context, long keyId) { - return getPGPSecretKeyRingWithKeyId(context, keyId).getSecretKey(keyId); - } 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; } @@ -102,7 +164,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); } @@ -111,7 +173,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); } @@ -124,12 +186,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); } @@ -139,11 +200,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 @@ -179,31 +240,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); } /** @@ -260,190 +333,22 @@ public class ProviderHelper { return ContentProviderOperation.newInsert(uri).withValues(values).build(); } - /** - * Private helper method - */ - private static ArrayList<Long> getKeyRingsMasterKeyIds(Context context, Uri queryUri) { - Cursor cursor = context.getContentResolver().query(queryUri, - new String[]{KeyRings.MASTER_KEY_ID}, null, null, null); - - ArrayList<Long> masterKeyIds = new ArrayList<Long>(); - 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); - } - - public static void deleteSecretKeyRing(Context context, long masterKeyId) { - ContentResolver cr = context.getContentResolver(); - 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)); + 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 - */ - 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); - - 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; - } - - 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<String> getKeyRingsAsArmoredString(Context context, Uri uri, - long[] masterKeyIds) { + public static ArrayList<String> getKeyRingsAsArmoredString(Context context, long[] masterKeyIds) { ArrayList<String> output = new ArrayList<String>(); 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)); @@ -493,48 +398,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 += ", "; @@ -543,9 +411,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; |