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:
Dominik Schürmann 2015-04-13 23:33:23 +02:00
commit f12c7b64d8
3 changed files with 119 additions and 39 deletions

View File

@ -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);
} }

View File

@ -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,

View File

@ -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"