aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDominik Schürmann <dominik@dominikschuermann.de>2015-11-23 09:06:12 +0100
committerDominik Schürmann <dominik@dominikschuermann.de>2015-11-23 09:06:12 +0100
commitc5bcbce28fa45d8d1e5714d111f3cc24a2c99d0e (patch)
treed7feab97088262b21343ae8e98955c0cc42b5378
parentdc631e5c1542b09e1359a861e98a2c03b93e05cd (diff)
downloadopen-keychain-c5bcbce28fa45d8d1e5714d111f3cc24a2c99d0e.tar.gz
open-keychain-c5bcbce28fa45d8d1e5714d111f3cc24a2c99d0e.tar.bz2
open-keychain-c5bcbce28fa45d8d1e5714d111f3cc24a2c99d0e.zip
Show notification when READ_CONTACTS permission is denied in sync service, hide linked contact card if permission is denied
-rw-r--r--OpenKeychain/src/main/AndroidManifest.xml18
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/CertifyOperation.java6
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/DeleteOperation.java2
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java2
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportOperation.java6
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/ContactSyncAdapterService.java57
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java12
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java4
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyFragment.java31
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ContactHelper.java55
-rw-r--r--OpenKeychain/src/main/res/values/strings.xml2
-rw-r--r--OpenKeychain/src/main/res/xml/cloud_search_preferences.xml (renamed from OpenKeychain/src/main/res/xml/cloud_search_prefs.xml)0
-rw-r--r--OpenKeychain/src/main/res/xml/proxy_preferences.xml (renamed from OpenKeychain/src/main/res/xml/proxy_prefs.xml)0
-rw-r--r--OpenKeychain/src/main/res/xml/sync_adapter_contacts.xml (renamed from OpenKeychain/src/main/res/xml/sync_adapter_desc.xml)0
-rw-r--r--OpenKeychain/src/main/res/xml/sync_adapter_contacts_structure.xml (renamed from OpenKeychain/src/main/res/xml/custom_pgp_contacts_structure.xml)0
-rw-r--r--OpenKeychain/src/main/res/xml/sync_adapter_keys.xml (renamed from OpenKeychain/src/main/res/xml/keyserver_sync_adapter_desc.xml)0
16 files changed, 148 insertions, 47 deletions
diff --git a/OpenKeychain/src/main/AndroidManifest.xml b/OpenKeychain/src/main/AndroidManifest.xml
index 79b8dbb27..337ad73e0 100644
--- a/OpenKeychain/src/main/AndroidManifest.xml
+++ b/OpenKeychain/src/main/AndroidManifest.xml
@@ -56,14 +56,20 @@
<!-- CAMERA permission requested by ZXing library -->
<!-- contact group -->
- <uses-permission android:name="android.permission.GET_ACCOUNTS" />
+ <!--
+ AUTHENTICATE_ACCOUNTS and MANAGE_ACCOUNTS removed in Android >= 6,
+ see https://code.google.com/p/android-developer-preview/issues/detail?id=2592
+ also READ_PROFILE, WRITE_PROFILE?
+ -->
<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
- <uses-permission android:name="android.permission.READ_CONTACTS" />
- <uses-permission android:name="android.permission.WRITE_CONTACTS" />
<uses-permission android:name="android.permission.READ_PROFILE" />
<uses-permission android:name="android.permission.WRITE_PROFILE" />
+ <uses-permission android:name="android.permission.GET_ACCOUNTS" />
+ <uses-permission android:name="android.permission.READ_CONTACTS" />
+ <uses-permission android:name="android.permission.WRITE_CONTACTS" />
+
<!-- storage group -->
<!--
No need on >= Android 4.4 for WRITE_EXTERNAL_STORAGE, because we use Storage Access Framework,
@@ -840,10 +846,10 @@
<meta-data
android:name="android.content.SyncAdapter"
- android:resource="@xml/sync_adapter_desc" />
+ android:resource="@xml/sync_adapter_contacts" />
<meta-data
android:name="android.provider.CONTACTS_STRUCTURE"
- android:resource="@xml/custom_pgp_contacts_structure" />
+ android:resource="@xml/sync_adapter_contacts_structure" />
</service>
<service
@@ -857,7 +863,7 @@
<meta-data
android:name="android.content.SyncAdapter"
- android:resource="@xml/keyserver_sync_adapter_desc" />
+ android:resource="@xml/sync_adapter_keys" />
</service>
<!-- Storage Provider for temporary decrypted files -->
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/CertifyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/CertifyOperation.java
index 7d11fa1f1..4ad75fde1 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/CertifyOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/CertifyOperation.java
@@ -18,14 +18,12 @@
package org.sufficientlysecure.keychain.operations;
-import java.net.Proxy;
import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicBoolean;
import android.content.Context;
import android.support.annotation.NonNull;
-import org.sufficientlysecure.keychain.keyimport.HkpKeyserver;
import org.sufficientlysecure.keychain.operations.results.CertifyResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
@@ -51,8 +49,6 @@ import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel.NfcSignOperationsBuilder;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.util.Passphrase;
-import org.sufficientlysecure.keychain.util.Preferences;
-import org.sufficientlysecure.keychain.util.orbot.OrbotHelper;
/**
* An operation which implements a high level user id certification operation.
@@ -256,7 +252,7 @@ public class CertifyOperation extends BaseOperation<CertifyActionsParcel> {
}
// since only verified keys are synced to contacts, we need to initiate a sync now
- ContactSyncAdapterService.requestSync();
+ ContactSyncAdapterService.requestContactsSync();
log.add(LogType.MSG_CRT_SUCCESS, 0);
if (uploadError != 0) {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/DeleteOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/DeleteOperation.java
index 56bd3b786..8227fea02 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/DeleteOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/DeleteOperation.java
@@ -102,7 +102,7 @@ public class DeleteOperation extends BaseOperation<DeleteKeyringParcel> {
int result = DeleteResult.RESULT_OK;
if (success > 0) {
// make sure new data is synced into contacts
- ContactSyncAdapterService.requestSync();
+ ContactSyncAdapterService.requestContactsSync();
log.add(LogType.MSG_DEL_OK, 0, success);
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java
index 3b2c484be..51485a35d 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java
@@ -195,7 +195,7 @@ public class EditKeyOperation extends BaseOperation<SaveKeyringParcel> {
updateProgress(R.string.progress_done, 100, 100);
// make sure new data is synced into contacts
- ContactSyncAdapterService.requestSync();
+ ContactSyncAdapterService.requestContactsSync();
log.add(LogType.MSG_ED_SUCCESS, 0);
return new EditKeyResult(EditKeyResult.RESULT_OK, log, ring.getMasterKeyId());
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportOperation.java
index 19a05790f..70288123f 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportOperation.java
@@ -124,7 +124,7 @@ public class ImportOperation extends BaseOperation<ImportKeyringParcel> {
/**
* Since the introduction of multithreaded import, we expect calling functions to handle the
- * contact-to-key sync i.e ContactSyncAdapterService.requestSync()
+ * contact-to-key sync i.e ContactSyncAdapterService.requestContactsSync()
*
* @param entries keys to import
* @param num number of keys to import
@@ -325,7 +325,7 @@ public class ImportOperation extends BaseOperation<ImportKeyringParcel> {
// Special: make sure new data is synced into contacts
// disabling sync right now since it reduces speed while multi-threading
// so, we expect calling functions to take care of it. KeychainService handles this
- // ContactSyncAdapterService.requestSync();
+ // ContactSyncAdapterService.requestContactsSync();
// convert to long array
long[] importedMasterKeyIdsArray = new long[importedMasterKeyIds.size()];
@@ -405,7 +405,7 @@ public class ImportOperation extends BaseOperation<ImportKeyringParcel> {
result = multiThreadedKeyImport(keyList.iterator(), keyList.size(), keyServer, proxy);
}
- ContactSyncAdapterService.requestSync();
+ ContactSyncAdapterService.requestContactsSync();
return result;
}
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 b36d23775..64f06fd15 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/ContactSyncAdapterService.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/ContactSyncAdapterService.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2014-2015 Dominik Schürmann <dominik@dominikschuermann.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -18,6 +18,9 @@
package org.sufficientlysecure.keychain.service;
import android.accounts.Account;
+import android.app.Activity;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
import android.app.Service;
import android.content.AbstractThreadedSyncAdapter;
import android.content.ContentProviderClient;
@@ -26,14 +29,20 @@ import android.content.Intent;
import android.content.SyncResult;
import android.os.Bundle;
import android.os.IBinder;
+import android.preference.PreferenceActivity;
import android.provider.ContactsContract;
+import android.support.v4.app.NotificationCompat;
import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.ui.SettingsActivity;
import org.sufficientlysecure.keychain.util.ContactHelper;
import org.sufficientlysecure.keychain.util.Log;
public class ContactSyncAdapterService extends Service {
+ private static final int NOTIFICATION_ID_SYNC_SETTINGS = 13;
+
private class ContactSyncAdapter extends AbstractThreadedSyncAdapter {
// private final AtomicBoolean importDone = new AtomicBoolean(false);
@@ -46,7 +55,44 @@ public class ContactSyncAdapterService extends Service {
public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider,
final SyncResult syncResult) {
Log.d(Constants.TAG, "Performing a contact sync!");
- // TODO: Import is currently disabled for 2.8, until we implement proper origin management
+
+ ContactHelper.writeKeysToContacts(ContactSyncAdapterService.this);
+
+ importKeys();
+ }
+
+ @Override
+ public void onSecurityException(Account account, Bundle extras, String authority, SyncResult syncResult) {
+ super.onSecurityException(account, extras, authority, syncResult);
+
+ // deactivate sync
+ ContentResolver.setSyncAutomatically(account, authority, false);
+
+ // show notification linking to sync settings
+ Intent resultIntent = new Intent(ContactSyncAdapterService.this, SettingsActivity.class);
+ resultIntent.putExtra(PreferenceActivity.EXTRA_SHOW_FRAGMENT,
+ SettingsActivity.SyncPrefsFragment.class.getName());
+ PendingIntent resultPendingIntent =
+ PendingIntent.getActivity(
+ ContactSyncAdapterService.this,
+ 0,
+ resultIntent,
+ PendingIntent.FLAG_UPDATE_CURRENT
+ );
+ NotificationCompat.Builder mBuilder =
+ new NotificationCompat.Builder(ContactSyncAdapterService.this)
+ .setSmallIcon(R.drawable.ic_stat_notify_24dp)
+ .setContentTitle(getString(R.string.sync_notification_permission_required_title))
+ .setContentText(getString(R.string.sync_notification_permission_required_text))
+ .setContentIntent(resultPendingIntent);
+ NotificationManager mNotifyMgr =
+ (NotificationManager) ContactSyncAdapterService.this.getSystemService(Activity.NOTIFICATION_SERVICE);
+ mNotifyMgr.notify(NOTIFICATION_ID_SYNC_SETTINGS, mBuilder.build());
+ }
+ }
+
+ private static void importKeys() {
+ // TODO: Import is currently disabled, until we implement proper origin management
// importDone.set(false);
// KeychainApplication.setupAccountAsNeeded(ContactSyncAdapterService.this);
// EmailKeyHelper.importContacts(getContext(), new Messenger(new Handler(Looper.getMainLooper(),
@@ -84,14 +130,13 @@ public class ContactSyncAdapterService extends Service {
// return;
// }
// }
- ContactHelper.writeKeysToContacts(ContactSyncAdapterService.this);
- }
}
- public static void requestSync() {
+ public static void requestContactsSync() {
Bundle extras = new Bundle();
- // no need to wait for internet connection!
+ // no need to wait, do it immediately
extras.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
+ extras.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true);
ContentResolver.requestSync(
new Account(Constants.ACCOUNT_NAME, Constants.ACCOUNT_TYPE),
ContactsContract.AUTHORITY,
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java
index 17398911c..9e962fa0d 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java
@@ -133,7 +133,7 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
super.onCreate(savedInstanceState);
// Load the preferences from an XML resource
- addPreferencesFromResource(R.xml.cloud_search_prefs);
+ addPreferencesFromResource(R.xml.cloud_search_preferences);
mKeyServerPreference = (PreferenceScreen) findPreference(Constants.Pref.KEY_SERVERS);
mKeyServerPreference.setSummary(keyserverSummary(getActivity()));
@@ -238,11 +238,11 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
if (mFragment != null) {
Preferences.setPreferenceManagerFileAndMode(mFragment.getPreferenceManager());
// Load the preferences from an XML resource
- mFragment.addPreferencesFromResource(R.xml.proxy_prefs);
+ mFragment.addPreferencesFromResource(R.xml.proxy_preferences);
} else {
Preferences.setPreferenceManagerFileAndMode(mActivity.getPreferenceManager());
// Load the preferences from an XML resource
- mActivity.addPreferencesFromResource(R.xml.proxy_prefs);
+ mActivity.addPreferencesFromResource(R.xml.proxy_preferences);
}
mUseTor = (SwitchPreference) automaticallyFindPreference(Constants.Pref.USE_TOR_PROXY);
@@ -509,9 +509,9 @@ public class SettingsActivity extends AppCompatPreferenceActivity {
// permission granted -> enable contact linking
AccountManager manager = AccountManager.get(getActivity());
final Account account = manager.getAccountsByType(Constants.ACCOUNT_TYPE)[0];
- SwitchPreference pref = (SwitchPreference) findPreference(Constants.Pref.SYNC_KEYSERVER);
- ContentResolver.setSyncAutomatically(account, Constants.PROVIDER_AUTHORITY, true);
- setSummary(pref, Constants.PROVIDER_AUTHORITY, true);
+ SwitchPreference pref = (SwitchPreference) findPreference(Constants.Pref.SYNC_CONTACTS);
+ ContentResolver.setSyncAutomatically(account, ContactsContract.AUTHORITY, true);
+ setSummary(pref, ContactsContract.AUTHORITY, true);
pref.setChecked(true);
}
}
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 c333ee0ef..e1b796f38 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java
@@ -855,8 +855,8 @@ public class ViewKeyActivity extends BaseNfcActivity implements
AsyncTask<Long, Void, Bitmap> photoTask =
new AsyncTask<Long, Void, Bitmap>() {
protected Bitmap doInBackground(Long... mMasterKeyId) {
- return ContactHelper.loadPhotoByMasterKeyId(getContentResolver(),
- mMasterKeyId[0], true);
+ return ContactHelper.loadPhotoByMasterKeyId(ViewKeyActivity.this,
+ getContentResolver(), mMasterKeyId[0], true);
}
protected void onPostExecute(Bitmap photo) {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyFragment.java
index 7be695de0..dda2a680a 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyFragment.java
@@ -22,10 +22,12 @@ package org.sufficientlysecure.keychain.ui;
import java.io.IOException;
import java.util.List;
+import android.Manifest;
import android.annotation.TargetApi;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.net.Uri;
@@ -35,6 +37,7 @@ import android.os.Bundle;
import android.os.Handler;
import android.provider.ContactsContract;
import android.support.v4.app.LoaderManager;
+import android.support.v4.content.ContextCompat;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.support.v7.widget.CardView;
@@ -241,9 +244,9 @@ public class ViewKeyFragment extends LoaderFragment implements
Bitmap picture;
if (mIsSecret) {
- picture = ContactHelper.loadMainProfilePhoto(resolver, false);
+ picture = ContactHelper.loadMainProfilePhoto(getActivity(), resolver, false);
} else {
- picture = ContactHelper.loadPhotoByContactId(resolver, contactId, false);
+ picture = ContactHelper.loadPhotoByContactId(getActivity(), resolver, contactId, false);
}
if (picture != null) mSystemContactPicture.setImageBitmap(picture);
@@ -419,13 +422,7 @@ public class ViewKeyFragment extends LoaderFragment implements
getLoaderManager().initLoader(LOADER_ID_LINKED_IDS, null, this);
}
-
- Bundle linkedContactData = new Bundle();
- linkedContactData.putLong(LOADER_EXTRA_LINKED_CONTACT_MASTER_KEY_ID, masterKeyId);
- linkedContactData.putBoolean(LOADER_EXTRA_LINKED_CONTACT_IS_SECRET, mIsSecret);
-
- // initialises loader for contact query so we can listen to any updates
- getLoaderManager().initLoader(LOADER_ID_LINKED_CONTACT, linkedContactData, this);
+ initLinkedContactLoader(masterKeyId, mIsSecret);
break;
}
@@ -465,6 +462,22 @@ public class ViewKeyFragment extends LoaderFragment implements
}
}
+ private void initLinkedContactLoader(long masterKeyId, boolean isSecret) {
+ if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.READ_CONTACTS)
+ == PackageManager.PERMISSION_DENIED) {
+ Log.w(Constants.TAG, "loading linked system contact not possible READ_CONTACTS permission denied!");
+ hideLinkedSystemContact();
+ return;
+ }
+
+ Bundle linkedContactData = new Bundle();
+ linkedContactData.putLong(LOADER_EXTRA_LINKED_CONTACT_MASTER_KEY_ID, masterKeyId);
+ linkedContactData.putBoolean(LOADER_EXTRA_LINKED_CONTACT_IS_SECRET, isSecret);
+
+ // initialises loader for contact query so we can listen to any updates
+ getLoaderManager().initLoader(LOADER_ID_LINKED_CONTACT, linkedContactData, this);
+ }
+
/**
* This is called when the last Cursor provided to onLoadFinished() above is about to be closed.
* We need to make sure we are no longer using it.
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ContactHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ContactHelper.java
index 77aa1a055..1abe56055 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ContactHelper.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ContactHelper.java
@@ -17,17 +17,21 @@
package org.sufficientlysecure.keychain.util;
+import android.Manifest;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.content.ContentProviderOperation;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
+import android.os.Build;
import android.provider.ContactsContract;
+import android.support.v4.content.ContextCompat;
import android.util.Patterns;
import org.sufficientlysecure.keychain.Constants;
@@ -51,6 +55,11 @@ public class ContactHelper {
private static final Map<Long, Bitmap> photoCache = new HashMap<>();
public static List<String> getPossibleUserEmails(Context context) {
+ if (!isContactsPermissionGranted(context)) {
+ Log.w(Constants.TAG, "getting emails not possible READ_CONTACTS permission denied!");
+ return new ArrayList<>();
+ }
+
Set<String> accountMails = getAccountEmails(context);
accountMails.addAll(getMainProfileContactEmails(context));
@@ -69,6 +78,11 @@ public class ContactHelper {
}
public static List<String> getPossibleUserNames(Context context) {
+ if (!isContactsPermissionGranted(context)) {
+ Log.w(Constants.TAG, "getting names not possible READ_CONTACTS permission denied!");
+ return new ArrayList<>();
+ }
+
Set<String> accountMails = getAccountEmails(context);
Set<String> names = getContactNamesFromEmails(context, accountMails);
names.addAll(getMainProfileContactName(context));
@@ -242,7 +256,7 @@ public class ContactHelper {
* @param highRes true for large image if present, false for thumbnail
* @return bitmap of loaded photo
*/
- public static Bitmap loadMainProfilePhoto(ContentResolver contentResolver, boolean highRes) {
+ public static Bitmap loadMainProfilePhoto(Context context, ContentResolver contentResolver, boolean highRes) {
try {
long mainProfileContactId = getMainProfileContactId(contentResolver);
@@ -300,6 +314,7 @@ public class ContactHelper {
}
public static Uri dataUriFromContactUri(Context context, Uri contactUri) {
+
Cursor contactMasterKey = context.getContentResolver().query(contactUri,
new String[]{ContactsContract.Data.DATA2}, null, null, null);
if (contactMasterKey != null) {
@@ -373,32 +388,43 @@ public class ContactHelper {
return contactName;
}
- public static Bitmap getCachedPhotoByMasterKeyId(ContentResolver contentResolver, long masterKeyId) {
+ public static Bitmap getCachedPhotoByMasterKeyId(Context context, ContentResolver contentResolver,
+ long masterKeyId) {
if (masterKeyId == -1) {
return null;
}
if (!photoCache.containsKey(masterKeyId)) {
- photoCache.put(masterKeyId, loadPhotoByMasterKeyId(contentResolver, masterKeyId, false));
+ photoCache.put(masterKeyId, loadPhotoByMasterKeyId(context, contentResolver, masterKeyId, false));
}
return photoCache.get(masterKeyId);
}
- public static Bitmap loadPhotoByMasterKeyId(ContentResolver contentResolver, long masterKeyId,
- boolean highRes) {
+ public static Bitmap loadPhotoByMasterKeyId(Context context, ContentResolver contentResolver,
+ long masterKeyId, boolean highRes) {
+ if (!isContactsPermissionGranted(context)) {
+ Log.w(Constants.TAG, "loading photo not possible READ_CONTACTS permission denied!");
+ return null;
+ }
+
if (masterKeyId == -1) {
return null;
}
try {
long contactId = findContactId(contentResolver, masterKeyId);
- return loadPhotoByContactId(contentResolver, contactId, highRes);
+ return loadPhotoByContactId(context, contentResolver, contactId, highRes);
} catch (Throwable ignored) {
return null;
}
}
- public static Bitmap loadPhotoByContactId(ContentResolver contentResolver, long contactId,
- boolean highRes) {
+ public static Bitmap loadPhotoByContactId(Context context, ContentResolver contentResolver,
+ long contactId, boolean highRes) {
+ if (!isContactsPermissionGranted(context)) {
+ Log.w(Constants.TAG, "loading photo not possible READ_CONTACTS permission denied!");
+ return null;
+ }
+
if (contactId == -1) {
return null;
}
@@ -452,6 +478,19 @@ public class ContactHelper {
writeKeysToNormalContacts(context, resolver);
}
+ private static boolean isContactsPermissionGranted(Context context) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
+ return true;
+ }
+
+ if (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_CONTACTS)
+ == PackageManager.PERMISSION_GRANTED) {
+ return true;
+ }
+
+ return false;
+ }
+
private static void writeKeysToNormalContacts(Context context, ContentResolver resolver) {
// delete raw contacts flagged for deletion by user so they can be reinserted
deleteFlaggedNormalRawContacts(resolver);
diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml
index 12917f515..38a619ad7 100644
--- a/OpenKeychain/src/main/res/values/strings.xml
+++ b/OpenKeychain/src/main/res/values/strings.xml
@@ -1505,6 +1505,8 @@
<string name="account_no_manual_account_creation">"You can not create OpenKeychain accounts manually."</string>
<string name="account_privacy_title">"Privacy"</string>
<string name="account_privacy_text">"OpenKeychain does not synchronize your contacts with the Internet. It only links contacts to keys based on names and email addresses. It does this offline on your device."</string>
+ <string name="sync_notification_permission_required_title">"Linking keys needs contacts access!"</string>
+ <string name="sync_notification_permission_required_text">"Touch to configure linking to contacts"</string>
<!-- Passphrase wizard -->
<!-- TODO: rename all the things! -->
diff --git a/OpenKeychain/src/main/res/xml/cloud_search_prefs.xml b/OpenKeychain/src/main/res/xml/cloud_search_preferences.xml
index 85d6a6bca..85d6a6bca 100644
--- a/OpenKeychain/src/main/res/xml/cloud_search_prefs.xml
+++ b/OpenKeychain/src/main/res/xml/cloud_search_preferences.xml
diff --git a/OpenKeychain/src/main/res/xml/proxy_prefs.xml b/OpenKeychain/src/main/res/xml/proxy_preferences.xml
index fbb83eb12..fbb83eb12 100644
--- a/OpenKeychain/src/main/res/xml/proxy_prefs.xml
+++ b/OpenKeychain/src/main/res/xml/proxy_preferences.xml
diff --git a/OpenKeychain/src/main/res/xml/sync_adapter_desc.xml b/OpenKeychain/src/main/res/xml/sync_adapter_contacts.xml
index a134fdebe..a134fdebe 100644
--- a/OpenKeychain/src/main/res/xml/sync_adapter_desc.xml
+++ b/OpenKeychain/src/main/res/xml/sync_adapter_contacts.xml
diff --git a/OpenKeychain/src/main/res/xml/custom_pgp_contacts_structure.xml b/OpenKeychain/src/main/res/xml/sync_adapter_contacts_structure.xml
index 39dd8bc91..39dd8bc91 100644
--- a/OpenKeychain/src/main/res/xml/custom_pgp_contacts_structure.xml
+++ b/OpenKeychain/src/main/res/xml/sync_adapter_contacts_structure.xml
diff --git a/OpenKeychain/src/main/res/xml/keyserver_sync_adapter_desc.xml b/OpenKeychain/src/main/res/xml/sync_adapter_keys.xml
index 3923fae59..3923fae59 100644
--- a/OpenKeychain/src/main/res/xml/keyserver_sync_adapter_desc.xml
+++ b/OpenKeychain/src/main/res/xml/sync_adapter_keys.xml