mirror of
https://github.com/moparisthebest/open-keychain
synced 2024-12-25 00:18:51 -05:00
Merge pull request #1193 from adithyaphilip/auto-refresh-contacts
Immediate display of contact card, fixed contact picture display issue, hides card if no contact
This commit is contained in:
commit
f12c7b64d8
@ -29,6 +29,7 @@ import android.provider.ContactsContract;
|
|||||||
import android.support.v4.app.LoaderManager;
|
import android.support.v4.app.LoaderManager;
|
||||||
import android.support.v4.content.CursorLoader;
|
import android.support.v4.content.CursorLoader;
|
||||||
import android.support.v4.content.Loader;
|
import android.support.v4.content.Loader;
|
||||||
|
import android.support.v7.widget.CardView;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
@ -37,7 +38,6 @@ import android.widget.*;
|
|||||||
import org.sufficientlysecure.keychain.Constants;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
import org.sufficientlysecure.keychain.R;
|
import org.sufficientlysecure.keychain.R;
|
||||||
import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround;
|
import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround;
|
||||||
import org.sufficientlysecure.keychain.pgp.KeyRing;
|
|
||||||
import org.sufficientlysecure.keychain.provider.KeychainContract;
|
import org.sufficientlysecure.keychain.provider.KeychainContract;
|
||||||
import org.sufficientlysecure.keychain.ui.adapter.UserIdsAdapter;
|
import org.sufficientlysecure.keychain.ui.adapter.UserIdsAdapter;
|
||||||
import org.sufficientlysecure.keychain.ui.dialog.UserIdInfoDialogFragment;
|
import org.sufficientlysecure.keychain.ui.dialog.UserIdInfoDialogFragment;
|
||||||
@ -55,14 +55,20 @@ public class ViewKeyFragment extends LoaderFragment implements
|
|||||||
//private ListView mLinkedSystemContact;
|
//private ListView mLinkedSystemContact;
|
||||||
|
|
||||||
boolean mIsSecret = false;
|
boolean mIsSecret = false;
|
||||||
boolean mSystemContactLoaded = false;
|
|
||||||
|
|
||||||
|
CardView mSystemContactCard;
|
||||||
LinearLayout mSystemContactLayout;
|
LinearLayout mSystemContactLayout;
|
||||||
ImageView mSystemContactPicture;
|
ImageView mSystemContactPicture;
|
||||||
TextView mSystemContactName;
|
TextView mSystemContactName;
|
||||||
|
|
||||||
private static final int LOADER_ID_UNIFIED = 0;
|
private static final int LOADER_ID_UNIFIED = 0;
|
||||||
private static final int LOADER_ID_USER_IDS = 1;
|
private static final int LOADER_ID_USER_IDS = 1;
|
||||||
|
private static final int LOADER_ID_LINKED_CONTACT = 2;
|
||||||
|
|
||||||
|
private static final String LOADER_EXTRA_LINKED_CONTACT_MASTER_KEY_ID
|
||||||
|
= "loader_linked_contact_master_key_id";
|
||||||
|
private static final String LOADER_EXTRA_LINKED_CONTACT_IS_SECRET
|
||||||
|
= "loader_linked_contact_is_secret";
|
||||||
|
|
||||||
private UserIdsAdapter mUserIdsAdapter;
|
private UserIdsAdapter mUserIdsAdapter;
|
||||||
|
|
||||||
@ -95,6 +101,7 @@ public class ViewKeyFragment extends LoaderFragment implements
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
mSystemContactCard = (CardView) view.findViewById(R.id.linked_system_contact_card);
|
||||||
mSystemContactLayout = (LinearLayout) view.findViewById(R.id.system_contact_layout);
|
mSystemContactLayout = (LinearLayout) view.findViewById(R.id.system_contact_layout);
|
||||||
mSystemContactName = (TextView) view.findViewById(R.id.system_contact_name);
|
mSystemContactName = (TextView) view.findViewById(R.id.system_contact_name);
|
||||||
mSystemContactPicture = (ImageView) view.findViewById(R.id.system_contact_picture);
|
mSystemContactPicture = (ImageView) view.findViewById(R.id.system_contact_picture);
|
||||||
@ -119,53 +126,60 @@ public class ViewKeyFragment extends LoaderFragment implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if a system contact exists for given masterKeyId, and if it does, sets name, picture
|
* Hides card if no linked system contact exists. Sets name, picture
|
||||||
* and onClickListener for the linked system contact's layout
|
* and onClickListener for the linked system contact's layout.
|
||||||
* In the case of a secret key, "me" contact details are loaded
|
* In the case of a secret key, "me" (own profile) contact details are loaded.
|
||||||
*
|
*
|
||||||
* @param masterKeyId
|
* @param contactId
|
||||||
*/
|
*/
|
||||||
private void loadLinkedSystemContact(final long masterKeyId) {
|
private void loadLinkedSystemContact(final long contactId) {
|
||||||
|
|
||||||
final Context context = mSystemContactName.getContext();
|
final Context context = mSystemContactName.getContext();
|
||||||
final ContentResolver resolver = context.getContentResolver();
|
final ContentResolver resolver = context.getContentResolver();
|
||||||
|
|
||||||
long contactId;
|
|
||||||
String contactName = null;
|
String contactName = null;
|
||||||
|
|
||||||
if (mIsSecret) {//all secret keys are linked to "me" profile in contacts
|
if (mIsSecret) {//all secret keys are linked to "me" profile in contacts
|
||||||
contactId = ContactHelper.getMainProfileContactId(resolver);
|
|
||||||
List<String> mainProfileNames = ContactHelper.getMainProfileContactName(context);
|
List<String> mainProfileNames = ContactHelper.getMainProfileContactName(context);
|
||||||
if (mainProfileNames != null && mainProfileNames.size() > 0) {
|
if (mainProfileNames != null && mainProfileNames.size() > 0) {
|
||||||
contactName = mainProfileNames.get(0);
|
contactName = mainProfileNames.get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
contactId = ContactHelper.findContactId(resolver, masterKeyId);
|
|
||||||
contactName = ContactHelper.getContactName(resolver, contactId);
|
contactName = ContactHelper.getContactName(resolver, contactId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (contactName != null) {//contact name exists for given master key
|
if (contactName != null) {//contact name exists for given master key
|
||||||
|
showLinkedSystemContact();
|
||||||
|
|
||||||
mSystemContactName.setText(contactName);
|
mSystemContactName.setText(contactName);
|
||||||
|
|
||||||
Bitmap picture;
|
Bitmap picture;
|
||||||
if (mIsSecret) {
|
if (mIsSecret) {
|
||||||
picture = ContactHelper.loadMainProfilePhoto(resolver, false);
|
picture = ContactHelper.loadMainProfilePhoto(resolver, false);
|
||||||
} else {
|
} else {
|
||||||
picture = ContactHelper.loadPhotoByMasterKeyId(resolver, masterKeyId, false);
|
picture = ContactHelper.loadPhotoByContactId(resolver, contactId, false);
|
||||||
}
|
}
|
||||||
if (picture != null) mSystemContactPicture.setImageBitmap(picture);
|
if (picture != null) mSystemContactPicture.setImageBitmap(picture);
|
||||||
|
|
||||||
final long finalContactId = contactId;
|
|
||||||
mSystemContactLayout.setOnClickListener(new View.OnClickListener() {
|
mSystemContactLayout.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
launchContactActivity(finalContactId, context);
|
launchContactActivity(contactId, context);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
mSystemContactLoaded = true;
|
} else {
|
||||||
|
hideLinkedSystemContact();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void hideLinkedSystemContact() {
|
||||||
|
mSystemContactCard.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showLinkedSystemContact() {
|
||||||
|
mSystemContactCard.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* launches the default android Contacts app to view a contact with the passed
|
* launches the default android Contacts app to view a contact with the passed
|
||||||
* contactId (CONTACT_ID column from ContactsContract.RawContact table which is _ID column in
|
* contactId (CONTACT_ID column from ContactsContract.RawContact table which is _ID column in
|
||||||
@ -195,7 +209,6 @@ public class ViewKeyFragment extends LoaderFragment implements
|
|||||||
loadData(dataUri);
|
loadData(dataUri);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// These are the rows that we will retrieve.
|
// These are the rows that we will retrieve.
|
||||||
static final String[] UNIFIED_PROJECTION = new String[]{
|
static final String[] UNIFIED_PROJECTION = new String[]{
|
||||||
KeychainContract.KeyRings._ID,
|
KeychainContract.KeyRings._ID,
|
||||||
@ -218,6 +231,12 @@ public class ViewKeyFragment extends LoaderFragment implements
|
|||||||
static final int INDEX_FINGERPRINT = 7;
|
static final int INDEX_FINGERPRINT = 7;
|
||||||
static final int INDEX_HAS_ENCRYPT = 8;
|
static final int INDEX_HAS_ENCRYPT = 8;
|
||||||
|
|
||||||
|
private static final String[] RAWCONTACT_PROJECTION = {
|
||||||
|
ContactsContract.RawContacts.CONTACT_ID
|
||||||
|
};
|
||||||
|
|
||||||
|
private static final int INDEX_CONTACT_ID = 0;
|
||||||
|
|
||||||
private void loadData(Uri dataUri) {
|
private void loadData(Uri dataUri) {
|
||||||
mDataUri = dataUri;
|
mDataUri = dataUri;
|
||||||
|
|
||||||
@ -241,6 +260,33 @@ public class ViewKeyFragment extends LoaderFragment implements
|
|||||||
case LOADER_ID_USER_IDS:
|
case LOADER_ID_USER_IDS:
|
||||||
return UserIdsAdapter.createLoader(getActivity(), mDataUri);
|
return UserIdsAdapter.createLoader(getActivity(), mDataUri);
|
||||||
|
|
||||||
|
//we need a separate loader for linked contact to ensure refreshing on verification
|
||||||
|
case LOADER_ID_LINKED_CONTACT: {
|
||||||
|
//passed in args to explicitly specify their need
|
||||||
|
long masterKeyId = args.getLong(LOADER_EXTRA_LINKED_CONTACT_MASTER_KEY_ID);
|
||||||
|
boolean isSecret = args.getBoolean(LOADER_EXTRA_LINKED_CONTACT_IS_SECRET);
|
||||||
|
|
||||||
|
Uri baseUri;
|
||||||
|
if (isSecret)
|
||||||
|
baseUri = ContactsContract.Profile.CONTENT_RAW_CONTACTS_URI;
|
||||||
|
else
|
||||||
|
baseUri = ContactsContract.RawContacts.CONTENT_URI;
|
||||||
|
|
||||||
|
return new CursorLoader(
|
||||||
|
getActivity(),
|
||||||
|
baseUri,
|
||||||
|
RAWCONTACT_PROJECTION,
|
||||||
|
ContactsContract.RawContacts.ACCOUNT_TYPE + "=? AND " +
|
||||||
|
ContactsContract.RawContacts.SOURCE_ID + "=? AND " +
|
||||||
|
ContactsContract.RawContacts.DELETED + "=?",
|
||||||
|
new String[]{//"0" for "not deleted"
|
||||||
|
Constants.ACCOUNT_TYPE,
|
||||||
|
Long.toString(masterKeyId),
|
||||||
|
"0"
|
||||||
|
},
|
||||||
|
null);
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -263,16 +309,26 @@ public class ViewKeyFragment extends LoaderFragment implements
|
|||||||
|
|
||||||
mIsSecret = data.getInt(INDEX_HAS_ANY_SECRET) != 0;
|
mIsSecret = data.getInt(INDEX_HAS_ANY_SECRET) != 0;
|
||||||
|
|
||||||
//TODO system to allow immediate refreshing of system contact on verification
|
|
||||||
if (!mSystemContactLoaded) {//ensure we load linked system contact only once
|
|
||||||
long masterKeyId = data.getLong(INDEX_MASTER_KEY_ID);
|
|
||||||
loadLinkedSystemContact(masterKeyId);
|
|
||||||
}
|
|
||||||
// load user ids after we know if it's a secret key
|
// load user ids after we know if it's a secret key
|
||||||
mUserIdsAdapter = new UserIdsAdapter(getActivity(), null, 0, !mIsSecret, null);
|
mUserIdsAdapter = new UserIdsAdapter(getActivity(), null, 0, !mIsSecret, null);
|
||||||
mUserIds.setAdapter(mUserIdsAdapter);
|
mUserIds.setAdapter(mUserIdsAdapter);
|
||||||
getLoaderManager().initLoader(LOADER_ID_USER_IDS, null, this);
|
getLoaderManager().initLoader(LOADER_ID_USER_IDS, null, this);
|
||||||
|
|
||||||
|
long masterKeyId = data.getLong(INDEX_MASTER_KEY_ID);
|
||||||
|
// we need to load linked contact here to prevent lag introduced by loader
|
||||||
|
// for the linked contact
|
||||||
|
long contactId = ContactHelper.findContactId(
|
||||||
|
getActivity().getContentResolver(),
|
||||||
|
masterKeyId);
|
||||||
|
loadLinkedSystemContact(contactId);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -282,6 +338,14 @@ public class ViewKeyFragment extends LoaderFragment implements
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case LOADER_ID_LINKED_CONTACT: {
|
||||||
|
if (data.moveToFirst()) {// if we have a linked contact
|
||||||
|
long contactId = data.getLong(INDEX_CONTACT_ID);
|
||||||
|
loadLinkedSystemContact(contactId);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
setContentShown(true);
|
setContentShown(true);
|
||||||
}
|
}
|
||||||
|
@ -220,15 +220,14 @@ public class ContactHelper {
|
|||||||
*/
|
*/
|
||||||
public static long getMainProfileContactId(ContentResolver resolver) {
|
public static long getMainProfileContactId(ContentResolver resolver) {
|
||||||
Cursor profileCursor = resolver.query(ContactsContract.Profile.CONTENT_URI,
|
Cursor profileCursor = resolver.query(ContactsContract.Profile.CONTENT_URI,
|
||||||
new String[]{ ContactsContract.Profile._ID}, null, null, null);
|
new String[]{ContactsContract.Profile._ID}, null, null, null);
|
||||||
|
|
||||||
if(profileCursor != null && profileCursor.getCount() != 0 && profileCursor.moveToNext()) {
|
if (profileCursor != null && profileCursor.getCount() != 0 && profileCursor.moveToNext()) {
|
||||||
long contactId = profileCursor.getLong(0);
|
long contactId = profileCursor.getLong(0);
|
||||||
profileCursor.close();
|
profileCursor.close();
|
||||||
return contactId;
|
return contactId;
|
||||||
}
|
} else {
|
||||||
else {
|
if (profileCursor != null) {
|
||||||
if(profileCursor != null) {
|
|
||||||
profileCursor.close();
|
profileCursor.close();
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
@ -330,7 +329,9 @@ public class ContactHelper {
|
|||||||
ContactsContract.RawContacts.SOURCE_ID + "=? AND " +
|
ContactsContract.RawContacts.SOURCE_ID + "=? AND " +
|
||||||
ContactsContract.RawContacts.DELETED + "=?",
|
ContactsContract.RawContacts.DELETED + "=?",
|
||||||
new String[]{//"0" for "not deleted"
|
new String[]{//"0" for "not deleted"
|
||||||
Constants.ACCOUNT_TYPE, Long.toString(masterKeyId), "0"
|
Constants.ACCOUNT_TYPE,
|
||||||
|
Long.toString(masterKeyId),
|
||||||
|
"0"
|
||||||
}, null);
|
}, null);
|
||||||
if (raw != null) {
|
if (raw != null) {
|
||||||
if (raw.moveToNext()) {
|
if (raw.moveToNext()) {
|
||||||
@ -385,23 +386,37 @@ public class ContactHelper {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
long rawContactId = findRawContactId(contentResolver, masterKeyId);
|
long contactId = findContactId(contentResolver, masterKeyId);
|
||||||
if (rawContactId == -1) {
|
return loadPhotoByContactId(contentResolver, contactId, highRes);
|
||||||
return null;
|
|
||||||
}
|
|
||||||
Uri rawContactUri = ContentUris.withAppendedId(ContactsContract.RawContacts.CONTENT_URI, rawContactId);
|
|
||||||
Uri contactUri = ContactsContract.RawContacts.getContactLookupUri(contentResolver, rawContactUri);
|
|
||||||
InputStream photoInputStream =
|
|
||||||
ContactsContract.Contacts.openContactPhotoInputStream(contentResolver, contactUri, highRes);
|
|
||||||
if (photoInputStream == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return BitmapFactory.decodeStream(photoInputStream);
|
|
||||||
} catch (Throwable ignored) {
|
} catch (Throwable ignored) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Bitmap loadPhotoByContactId(ContentResolver contentResolver, long contactId,
|
||||||
|
boolean highRes) {
|
||||||
|
if (contactId == -1) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Uri contactUri = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, contactId);
|
||||||
|
// older android versions (tested on API level 15) fail on lookupuris being passed to
|
||||||
|
// openContactPhotoInputStream
|
||||||
|
// http://stackoverflow.com/a/21214524/3000919
|
||||||
|
// Uri lookupUri = ContactsContract.Contacts.getLookupUri(contentResolver, contactUri);
|
||||||
|
// Also, we don't need a permanent shortcut to the contact since we load it afresh each time
|
||||||
|
|
||||||
|
InputStream photoInputStream = ContactsContract.Contacts.openContactPhotoInputStream(
|
||||||
|
contentResolver,
|
||||||
|
contactUri,
|
||||||
|
highRes);
|
||||||
|
|
||||||
|
if (photoInputStream == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return BitmapFactory.decodeStream(photoInputStream);
|
||||||
|
}
|
||||||
|
|
||||||
public static final String[] KEYS_TO_CONTACT_PROJECTION = new String[]{
|
public static final String[] KEYS_TO_CONTACT_PROJECTION = new String[]{
|
||||||
KeychainContract.KeyRings.MASTER_KEY_ID,
|
KeychainContract.KeyRings.MASTER_KEY_ID,
|
||||||
KeychainContract.KeyRings.USER_ID,
|
KeychainContract.KeyRings.USER_ID,
|
||||||
|
@ -46,6 +46,7 @@
|
|||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:visibility="gone"
|
||||||
card_view:cardBackgroundColor="@android:color/white"
|
card_view:cardBackgroundColor="@android:color/white"
|
||||||
card_view:cardElevation="2dp"
|
card_view:cardElevation="2dp"
|
||||||
card_view:cardUseCompatPadding="true"
|
card_view:cardUseCompatPadding="true"
|
||||||
|
Loading…
Reference in New Issue
Block a user