aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormar-v-in <github@rvin.mooo.com>2014-06-05 23:22:21 +0200
committermar-v-in <github@rvin.mooo.com>2014-06-05 23:22:21 +0200
commit80e99986401b635f4eeef5d13740911d10740aef (patch)
treeaed9056765590de9d251380aa881a8c0655a3fb2
parentdc1e26f39c9c7fa88dd28d2920a2919f83e0575c (diff)
downloadopen-keychain-80e99986401b635f4eeef5d13740911d10740aef.tar.gz
open-keychain-80e99986401b635f4eeef5d13740911d10740aef.tar.bz2
open-keychain-80e99986401b635f4eeef5d13740911d10740aef.zip
Show keys with android contacts
This means to sync userid + keyid into contact storage. Android will merge them to normal contacts based on primary userid.
-rw-r--r--OpenKeychain/src/main/AndroidManifest.xml6
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java2
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java11
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/ContactHelper.java89
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/ContactSyncAdapterService.java4
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java13
-rw-r--r--OpenKeychain/src/main/res/values/strings.xml1
-rw-r--r--OpenKeychain/src/main/res/xml/custom_pgp_contacts_structure.xml4
8 files changed, 119 insertions, 11 deletions
diff --git a/OpenKeychain/src/main/AndroidManifest.xml b/OpenKeychain/src/main/AndroidManifest.xml
index 9a2011205..31c809334 100644
--- a/OpenKeychain/src/main/AndroidManifest.xml
+++ b/OpenKeychain/src/main/AndroidManifest.xml
@@ -58,6 +58,7 @@
<uses-permission android:name="android.permission.READ_SYNC_SETTINGS"/>
<uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS"/>
<uses-permission android:name="android.permission.READ_CONTACTS" />
+ <uses-permission android:name="android.permission.WRITE_CONTACTS" />
<!-- android:allowBackup="false": Don't allow backup over adb backup or other apps! -->
<application
@@ -91,6 +92,11 @@
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".ui.KeyListActivity" />
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <data android:mimeType="vnd.android.cursor.item/vnd.org.sufficientlysecure.keychain.key" />
+ </intent-filter>
</activity>
<activity
android:name=".ui.ViewCertActivity"
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java
index 0fd109484..c769da421 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java
@@ -46,6 +46,8 @@ public final class Constants {
public static final String INTENT_PREFIX = PACKAGE_NAME + ".action.";
+ public static final String CUSTOM_CONTACT_DATA_MIME_TYPE = "vnd.android.cursor.item/vnd.org.sufficientlysecure.keychain.key";
+
public static final class Path {
public static final String APP_DIR = Environment.getExternalStorageDirectory()
+ "/OpenKeychain";
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java
index 3ac3a9dee..5d6a62f9c 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java
@@ -26,6 +26,7 @@ import android.graphics.drawable.Drawable;
import android.os.Environment;
import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.sufficientlysecure.keychain.helper.ContactHelper;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.PRNGFixes;
@@ -79,14 +80,14 @@ public class KeychainApplication extends Application {
brandGlowEffect(getApplicationContext(),
getApplicationContext().getResources().getColor(R.color.emphasis));
- setupAccountAsNeeded();
+ setupAccountAsNeeded(this);
}
- private void setupAccountAsNeeded() {
- AccountManager manager = AccountManager.get(this);
- Account[] accounts = manager.getAccountsByType(getPackageName());
+ public static void setupAccountAsNeeded(Context context) {
+ AccountManager manager = AccountManager.get(context);
+ Account[] accounts = manager.getAccountsByType(Constants.PACKAGE_NAME);
if (accounts == null || accounts.length == 0) {
- Account dummy = new Account(getString(R.string.app_name), getPackageName());
+ Account dummy = new Account(context.getString(R.string.app_name), Constants.PACKAGE_NAME);
manager.addAccountExplicitly(dummy, null, null);
}
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/ContactHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/ContactHelper.java
index 583543c4a..4b85d7e80 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/ContactHelper.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/ContactHelper.java
@@ -19,11 +19,17 @@ package org.sufficientlysecure.keychain.helper;
import android.accounts.Account;
import android.accounts.AccountManager;
-import android.content.ContentResolver;
-import android.content.Context;
+import android.content.*;
import android.database.Cursor;
+import android.net.Uri;
+import android.os.RemoteException;
import android.provider.ContactsContract;
import android.util.Patterns;
+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.util.Log;
import java.util.ArrayList;
import java.util.HashSet;
@@ -32,6 +38,15 @@ import java.util.Set;
public class ContactHelper {
+ public static final String[] KEYS_TO_CONTACT_PROJECTION = new String[]{
+ KeychainContract.KeyRings.USER_ID,
+ KeychainContract.KeyRings.FINGERPRINT,
+ KeychainContract.KeyRings.KEY_ID,
+ KeychainContract.KeyRings.MASTER_KEY_ID};
+ public static final String[] RAW_CONTACT_ID_PROJECTION = new String[]{ContactsContract.RawContacts._ID};
+ public static final String FIND_RAW_CONTACT_SELECTION =
+ ContactsContract.RawContacts.ACCOUNT_TYPE + "=? AND " + ContactsContract.RawContacts.SOURCE_ID + "=?";
+
public static final List<String> getMailAccounts(Context context) {
final Account[] accounts = AccountManager.get(context).getAccounts();
final Set<String> emailSet = new HashSet<String>();
@@ -60,4 +75,74 @@ public class ContactHelper {
mailCursor.close();
return new ArrayList<String>(mails);
}
+
+ public static Uri dataUriFromContactUri(Context context, Uri contactUri) {
+ Cursor contactMasterKey = context.getContentResolver().query(contactUri, new String[]{ContactsContract.Data.DATA2}, null, null, null, null);
+ if (contactMasterKey != null) {
+ if (contactMasterKey.moveToNext()) {
+ return KeychainContract.KeyRings.buildGenericKeyRingUri(contactMasterKey.getLong(0));
+ }
+ contactMasterKey.close();
+ }
+ return null;
+ }
+
+ public static void writeKeysToContacts(Context context) {
+ ContentResolver resolver = context.getContentResolver();
+ Cursor cursor = resolver.query(KeychainContract.KeyRings.buildUnifiedKeyRingsUri(), KEYS_TO_CONTACT_PROJECTION,
+ null, null, null);
+ if (cursor != null) {
+ while (cursor.moveToNext()) {
+ String[] userId = PgpKeyHelper.splitUserId(cursor.getString(0));
+ String fingerprint = PgpKeyHelper.convertFingerprintToHex(cursor.getBlob(1));
+ String keyIdShort = PgpKeyHelper.convertKeyIdToHexShort(cursor.getLong(2));
+ long masterKeyId = cursor.getLong(3);
+ int rawContactId = -1;
+ Cursor raw = resolver.query(ContactsContract.RawContacts.CONTENT_URI, RAW_CONTACT_ID_PROJECTION,
+ FIND_RAW_CONTACT_SELECTION, new String[]{Constants.PACKAGE_NAME, fingerprint}, null, null);
+ if (raw != null) {
+ if (raw.moveToNext()) {
+ rawContactId = raw.getInt(0);
+ }
+ raw.close();
+ }
+ ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
+ if (rawContactId == -1) {
+ ops.add(ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
+ .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, context.getString(R.string.app_name))
+ .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, Constants.PACKAGE_NAME)
+ .withValue(ContactsContract.RawContacts.SOURCE_ID, fingerprint)
+ .build());
+ if (userId[0] != null) {
+ ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
+ .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
+ .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
+ .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, userId[0])
+ .build());
+ }
+ if (userId[1] != null) {
+ ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
+ .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
+ .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE)
+ .withValue(ContactsContract.CommonDataKinds.Email.DATA, userId[1])
+ .build());
+ }
+ ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
+ .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
+ .withValue(ContactsContract.Data.MIMETYPE, Constants.CUSTOM_CONTACT_DATA_MIME_TYPE)
+ .withValue(ContactsContract.Data.DATA1, String.format(context.getString(R.string.contact_show_key), keyIdShort))
+ .withValue(ContactsContract.Data.DATA2, masterKeyId)
+ .build());
+ }
+ try {
+ resolver.applyBatch(ContactsContract.AUTHORITY, ops);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ } catch (OperationApplicationException e) {
+ e.printStackTrace();
+ }
+ }
+ cursor.close();
+ }
+ }
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/ContactSyncAdapterService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/ContactSyncAdapterService.java
index 4d0397196..a52dbfa27 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/ContactSyncAdapterService.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/ContactSyncAdapterService.java
@@ -24,6 +24,8 @@ import android.content.ContentProviderClient;
import android.content.Intent;
import android.content.SyncResult;
import android.os.*;
+import org.sufficientlysecure.keychain.KeychainApplication;
+import org.sufficientlysecure.keychain.helper.ContactHelper;
import org.sufficientlysecure.keychain.helper.EmailKeyHelper;
import org.sufficientlysecure.keychain.util.Log;
@@ -60,6 +62,8 @@ public class ContactSyncAdapterService extends Service {
}
}
})));
+ KeychainApplication.setupAccountAsNeeded(ContactSyncAdapterService.this);
+ ContactHelper.writeKeysToContacts(ContactSyncAdapterService.this);
}
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java
index bed116f5f..010144851 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java
@@ -20,6 +20,7 @@ package org.sufficientlysecure.keychain.ui;
import android.annotation.TargetApi;
import android.app.Activity;
+import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
@@ -32,6 +33,7 @@ import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
+import android.provider.ContactsContract;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
@@ -47,6 +49,7 @@ import com.devspark.appmsg.AppMsg;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.helper.ContactHelper;
import org.sufficientlysecure.keychain.helper.ExportHelper;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.provider.KeychainContract;
@@ -125,7 +128,7 @@ public class ViewKeyActivity extends ActionBarActivity implements
switchToTab = intent.getExtras().getInt(EXTRA_SELECTED_TAB);
}
- Uri dataUri = getIntent().getData();
+ Uri dataUri = getDataUri();
if (dataUri == null) {
Log.e(Constants.TAG, "Data missing. Should be Uri of key!");
finish();
@@ -163,6 +166,14 @@ public class ViewKeyActivity extends ActionBarActivity implements
mViewPager.setCurrentItem(switchToTab);
}
+ private Uri getDataUri() {
+ Uri dataUri = getIntent().getData();
+ if (dataUri != null && dataUri.getHost().equals(ContactsContract.AUTHORITY)) {
+ dataUri = ContactHelper.dataUriFromContactUri(this, dataUri);
+ }
+ return dataUri;
+ }
+
private void loadData(Uri dataUri) {
mDataUri = dataUri;
diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml
index 09f76c675..ec6b389ed 100644
--- a/OpenKeychain/src/main/res/values/strings.xml
+++ b/OpenKeychain/src/main/res/values/strings.xml
@@ -521,5 +521,6 @@
<string name="error_no_encrypt_subkey">No encryption subkey available!</string>
<string name="info_no_manual_account_creation">Do not create OpenKeychain-Accounts manually.
For more information, see Help.</string>
+ <string name="contact_show_key">Show key (%s)</string>
</resources>
diff --git a/OpenKeychain/src/main/res/xml/custom_pgp_contacts_structure.xml b/OpenKeychain/src/main/res/xml/custom_pgp_contacts_structure.xml
index 3318f3b45..5f5f2be80 100644
--- a/OpenKeychain/src/main/res/xml/custom_pgp_contacts_structure.xml
+++ b/OpenKeychain/src/main/res/xml/custom_pgp_contacts_structure.xml
@@ -1,7 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<ContactsSource xmlns:android="http://schemas.android.com/apk/res/android">
<ContactsDataKind android:mimeType="vnd.android.cursor.item/vnd.org.sufficientlysecure.keychain.key"
- android:icon="@drawable/key_small"
- android:summaryColumn="data1"
- android:detailColumn="data2"/>
+ android:detailColumn="data1"/>
</ContactsSource> \ No newline at end of file