updates to conversation menu, and updating of group info

// FREEBIE
This commit is contained in:
Jake McGinty 2014-02-20 15:41:52 -08:00
parent 7667264789
commit 7beab36c6a
13 changed files with 348 additions and 53 deletions

View File

@ -25,7 +25,7 @@
android:layout_height="70dp"
position="bottom_right"
android:layout_marginRight="10dp"
android:src="@drawable/icon"
android:src="@drawable/ic_group_photo"
android:contentDescription="@string/GroupCreateActivity_avatar_content_description" />
<EditText android:id="@+id/group_name"

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/menu_edit_group"
android:title="@string/conversation__menu_update_group"
android:showAsAction="collapseActionView" />
<item android:id="@+id/menu_leave"
android:title="@string/conversation__menu_leave_group"
android:showAsAction="collapseActionView"/>
</menu>

View File

@ -7,10 +7,6 @@
<menu>
<item android:title="@string/conversation_secure_verified__menu_verify_recipient"
android:id="@+id/menu_verify_recipient"/>
<item android:title="@string/conversation_secure_verified__menu_abort_secure_session"
android:id="@+id/menu_abort_session"/>
</menu>
</item>
</menu>

View File

@ -8,10 +8,6 @@
<item android:title="@string/conversation_secure_verified__menu_no_identity"
android:enabled="false"
android:id="@+id/menu_no_identity" />
<item android:title="@string/conversation_secure_verified__menu_abort_secure_session"
android:id="@+id/menu_abort_session"/>
</menu>
</item>
</menu>

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:title="@string/conversation_secure_verified__menu_security"
android:id="@+id/menu_security"
android:icon="?menu_lock_icon"
android:showAsAction="ifRoom">
<menu>
<item android:title="@string/conversation_secure_verified__menu_abort_secure_session"
android:id="@+id/menu_abort_session"/>
</menu>
</item>
</menu>

View File

@ -124,10 +124,12 @@
<!-- GroupCreateActivity -->
<string name="GroupCreateActivity_actionbar_title">New Group</string>
<string name="GroupCreateActivity_actionbar_update_title">Update Group</string>
<string name="GroupCreateActivity_group_name_hint">Group Name</string>
<string name="GroupCreateActivity_actionbar_mms_title">New MMS Group</string>
<string name="GroupCreateActivity_contacts_dont_support_push">You have selected a contact that doesn\'t support TextSecure groups, so this group will be MMS.</string>
<string name="GroupCreateActivity_you_dont_support_push">You\'re not registered for using the data channel, so TextSecure groups are disabled.</string>
<string name="GroupCreateActivity_you_dont_own_this_group">You\'re not the owner of this group, so you cannot edit the title or picture.</string>
<string name="GroupCreateActivity_contacts_mms_exception">An unexpected error happened that has made group creation fail.</string>
<string name="GroupCreateActivity_contacts_no_members">You need at least one person in your group!</string>
<string name="GroupCreateActivity_contacts_invalid_number">One of the members of your group has a number that can\'t be read correctly. Please fix or remove that contact and try again.</string>
@ -563,6 +565,7 @@
<!-- recipients_panel -->
<string name="recipients_panel__to">To</string>
<string name="recipients_panel__add_member">Add member</string>
<!-- review_identities -->
<string name="review_identities__you_don_t_currently_have_any_identity_keys_in_your_trust_database">You don\'t currently have any identity keys in your trust database.</string>
@ -725,6 +728,8 @@
<!-- conversation -->
<string name="conversation__menu_add_attachment">Add attachment</string>
<string name="conversation__menu_update_group">Update Group</string>
<string name="conversation__menu_leave_group">Leave Group</string>
<string name="conversation__menu_add_contact_info">Add contact info</string>
<string name="conversation__menu_delete_thread">Delete thread</string>

View File

@ -75,6 +75,7 @@ import org.thoughtcrime.securesms.mms.SlideDeck;
import org.thoughtcrime.securesms.notifications.MessageNotifier;
import org.thoughtcrime.securesms.protocol.Tag;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientFactory;
import org.thoughtcrime.securesms.recipients.RecipientFormattingException;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.service.KeyCachingService;
@ -132,6 +133,7 @@ public class ConversationActivity extends PassphraseRequiredSherlockFragmentActi
private static final int PICK_VIDEO = 3;
private static final int PICK_AUDIO = 4;
private static final int PICK_CONTACT_INFO = 5;
private static final int GROUP_EDIT = 6;
private MasterSecret masterSecret;
private RecipientsPanel recipientsPanel;
@ -234,6 +236,10 @@ public class ConversationActivity extends PassphraseRequiredSherlockFragmentActi
case PICK_CONTACT_INFO:
addContactInfo(data.getData());
break;
case GROUP_EDIT:
this.recipients = RecipientFactory.getRecipientsForIds(this, String.valueOf(getRecipients().getPrimaryRecipient().getRecipientId()), false);
initializeTitleBar();
break;
}
}
@ -242,13 +248,18 @@ public class ConversationActivity extends PassphraseRequiredSherlockFragmentActi
MenuInflater inflater = this.getSupportMenuInflater();
menu.clear();
boolean pushRegistered = TextSecurePreferences.isPushRegistered(this);
if (isSingleConversation() && isEncryptedConversation) {
if (isAuthenticatedConversation) {
inflater.inflate(R.menu.conversation_secure_identity, menu);
} else {
inflater.inflate(R.menu.conversation_secure_no_identity, menu);
}
} else if (isSingleConversation()) {
if (!pushRegistered) {
inflater.inflate(R.menu.conversation_secure_sms, menu);
}
} else if (isSingleConversation() && !pushRegistered) {
inflater.inflate(R.menu.conversation_insecure, menu);
}
@ -264,6 +275,8 @@ public class ConversationActivity extends PassphraseRequiredSherlockFragmentActi
} else {
menu.findItem(R.id.menu_distribution_conversation).setChecked(true);
}
} else {
inflater.inflate(R.menu.conversation_push_group_options, menu);
}
}
@ -286,12 +299,25 @@ public class ConversationActivity extends PassphraseRequiredSherlockFragmentActi
case R.id.menu_group_recipients: handleDisplayGroupRecipients(); return true;
case R.id.menu_distribution_broadcast: handleDistributionBroadcastEnabled(item); return true;
case R.id.menu_distribution_conversation: handleDistributionConversationEnabled(item); return true;
case R.id.menu_edit_group: handleEditPushGroup(); return true;
case R.id.menu_leave: handleLeavePushGroup(); return true;
case android.R.id.home: handleReturnToConversationList(); return true;
}
return false;
}
private void handleLeavePushGroup() {
Toast.makeText(getApplicationContext(), "not yet implemented", Toast.LENGTH_SHORT).show();
}
private void handleEditPushGroup() {
Intent intent = new Intent(ConversationActivity.this, GroupCreateActivity.class);
intent.putExtra(GroupCreateActivity.MASTER_SECRET_EXTRA, masterSecret);
intent.putExtra(GroupCreateActivity.GROUP_RECIPIENT_EXTRA, recipients);
startActivityForResult(intent, GROUP_EDIT);
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
if (isEncryptedConversation) {

View File

@ -1,6 +1,7 @@
package org.thoughtcrime.securesms;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
@ -11,6 +12,7 @@ import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.Log;
import android.util.Pair;
@ -28,12 +30,14 @@ import com.google.protobuf.ByteString;
import org.thoughtcrime.securesms.components.PushRecipientsPanel;
import org.thoughtcrime.securesms.contacts.ContactAccessor;
import org.thoughtcrime.securesms.contacts.RecipientsEditor;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.GroupDatabase;
import org.thoughtcrime.securesms.database.ThreadDatabase;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientFactory;
import org.thoughtcrime.securesms.recipients.RecipientFormattingException;
import org.thoughtcrime.securesms.recipients.RecipientProvider;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.sms.MessageSender;
import org.thoughtcrime.securesms.mms.OutgoingGroupMediaMessage;
@ -49,6 +53,7 @@ import org.whispersystems.textsecure.crypto.MasterSecret;
import org.whispersystems.textsecure.directory.Directory;
import org.whispersystems.textsecure.directory.NotInDirectoryException;
import org.whispersystems.textsecure.util.InvalidNumberException;
import org.whispersystems.textsecure.util.PhoneNumberFormatter;
import java.io.ByteArrayOutputStream;
import java.io.File;
@ -70,7 +75,8 @@ public class GroupCreateActivity extends PassphraseRequiredSherlockFragmentActiv
private final static String TAG = GroupCreateActivity.class.getSimpleName();
public static final String GROUP_RECIPIENT_EXTRA = "group_recipient";
public static final String GROUP_THREAD_EXTRA = "group_thread";
public static final String MASTER_SECRET_EXTRA = "master_secret";
private final DynamicTheme dynamicTheme = new DynamicTheme();
@ -87,10 +93,17 @@ public class GroupCreateActivity extends PassphraseRequiredSherlockFragmentActiv
private PushRecipientsPanel recipientsPanel;
private ImageView avatar;
private TextView creatingText;
private ProgressDialog pd;
private Recipients groupRecipient = null;
private long groupThread = -1;
private byte[] groupId = null;
private Set<Recipient> existingContacts = null;
private String existingTitle = null;
private Bitmap existingAvatarBmp = null;
private MasterSecret masterSecret;
private Bitmap avatarBmp;
private Set<Recipient> selectedContacts;
@Override
@ -124,10 +137,9 @@ public class GroupCreateActivity extends PassphraseRequiredSherlockFragmentActiv
private void disableWhisperGroupUi(int reasonResId) {
View pushDisabled = findViewById(R.id.push_disabled);
pushDisabled.setVisibility(View.VISIBLE);
((TextView)findViewById(R.id.push_disabled_reason)).setText(reasonResId);
((TextView) findViewById(R.id.push_disabled_reason)).setText(reasonResId);
avatar.setEnabled(false);
groupName.setEnabled(false);
getSupportActionBar().setTitle(R.string.GroupCreateActivity_actionbar_mms_title);
}
private void enableWhisperGroupUi() {
@ -135,7 +147,7 @@ public class GroupCreateActivity extends PassphraseRequiredSherlockFragmentActiv
avatar.setEnabled(true);
groupName.setEnabled(true);
final CharSequence groupNameText = groupName.getText();
if (groupNameText.length() > 0)
if (groupNameText != null && groupNameText.length() > 0)
getSupportActionBar().setTitle(groupNameText);
else
getSupportActionBar().setTitle(R.string.GroupCreateActivity_actionbar_title);
@ -155,8 +167,12 @@ public class GroupCreateActivity extends PassphraseRequiredSherlockFragmentActiv
}
private void addSelectedContact(Recipient contact) {
if (!selectedContacts.contains(contact) && (existingContacts == null || !existingContacts.contains(contact)))
selectedContacts.add(contact);
if (!isActiveInDirectory(this, contact)) disableWhisperGroupUi(R.string.GroupCreateActivity_contacts_dont_support_push);
if (!isActiveInDirectory(this, contact)) {
disableWhisperGroupUi(R.string.GroupCreateActivity_contacts_dont_support_push);
getSupportActionBar().setTitle(R.string.GroupCreateActivity_actionbar_mms_title);
}
}
private void addAllSelectedContacts(Collection<Recipient> contacts) {
@ -177,6 +193,23 @@ public class GroupCreateActivity extends PassphraseRequiredSherlockFragmentActiv
}
private void initializeResources() {
groupRecipient = getIntent().getParcelableExtra(GROUP_RECIPIENT_EXTRA);
groupThread = getIntent().getLongExtra(GROUP_THREAD_EXTRA, -1);
if (groupRecipient != null) {
final String encodedGroupId = groupRecipient.getPrimaryRecipient().getNumber();
if (encodedGroupId != null) {
try {
groupId = GroupUtil.getDecodedId(encodedGroupId);
} catch (IOException ioe) {
Log.w(TAG, "Couldn't decode the encoded groupId passed in via intent", ioe);
groupId = null;
}
if (groupId != null) {
new FillExistingGroupInfoAsyncTask().execute();
}
}
}
masterSecret = getIntent().getParcelableExtra(MASTER_SECRET_EXTRA);
lv = (ListView) findViewById(R.id.selected_contacts_list);
@ -192,14 +225,18 @@ public class GroupCreateActivity extends PassphraseRequiredSherlockFragmentActiv
public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) { }
@Override
public void afterTextChanged(Editable editable) {
if (editable.length() > 0)
getSupportActionBar().setTitle(getString(R.string.GroupCreateActivity_actionbar_title) + ": " + editable.toString());
else
if (editable.length() > 0) {
final int prefixResId = (groupId != null)
? R.string.GroupCreateActivity_actionbar_update_title
: R.string.GroupCreateActivity_actionbar_title;
getSupportActionBar().setTitle(getString(prefixResId) + ": " + editable.toString());
} else {
getSupportActionBar().setTitle(R.string.GroupCreateActivity_actionbar_title);
}
}
});
SelectedRecipientsAdapter adapter = new SelectedRecipientsAdapter(this, android.R.id.text1, new ArrayList<Recipient>());
SelectedRecipientsAdapter adapter = new SelectedRecipientsAdapter(this, android.R.id.text1, new ArrayList<SelectedRecipientsAdapter.RecipientWrapper>());
adapter.setOnRecipientDeletedListener(new SelectedRecipientsAdapter.OnRecipientDeletedListener() {
@Override
public void onRecipientDeleted(Recipient recipient) {
@ -235,6 +272,8 @@ public class GroupCreateActivity extends PassphraseRequiredSherlockFragmentActiv
startActivityForResult(photoPickerIntent, PICK_AVATAR);
}
});
((RecipientsEditor)findViewById(R.id.recipients_text)).setHint(R.string.recipients_panel__add_member);
}
private Uri getTempUri() {
@ -276,7 +315,8 @@ public class GroupCreateActivity extends PassphraseRequiredSherlockFragmentActiv
finish();
return true;
case R.id.menu_create_group:
handleGroupCreate();
if (groupId == null) handleGroupCreate();
else handleGroupUpdate();
return true;
}
@ -297,6 +337,75 @@ public class GroupCreateActivity extends PassphraseRequiredSherlockFragmentActiv
}
}
private static List<String> recipientsToNormalizedStrings(Collection<Recipient> recipients, String localNumber) {
final List<String> e164numbers = new ArrayList<String>(recipients.size());
for (Recipient contact : recipients) {
try {
e164numbers.add(PhoneNumberFormatter.formatNumber(contact.getNumber(), localNumber));
} catch (InvalidNumberException ine) {
Log.w(TAG, "Failed to format number for added group member.", ine);
}
}
return e164numbers;
}
private void handleGroupUpdate() {
Log.i(TAG, "Updating group info.");
GroupDatabase db = DatabaseFactory.getGroupDatabase(this);
final String localNumber = TextSecurePreferences.getLocalNumber(this);
List<String> e164numbers = recipientsToNormalizedStrings(selectedContacts, localNumber);
if (selectedContacts.size() > 0) {
db.add(groupId, localNumber, e164numbers);
GroupContext context = GroupContext.newBuilder()
.setId(ByteString.copyFrom(groupId))
.setType(GroupContext.Type.ADD)
.addAllMembers(e164numbers)
.build();
OutgoingGroupMediaMessage outgoingMessage = new OutgoingGroupMediaMessage(this, groupRecipient, context, null);
try {
MessageSender.send(this, masterSecret, outgoingMessage, groupThread);
} catch (MmsException me) {
Log.w(TAG, "MmsException encountered when trying to add members to group.", me);
}
}
GroupContext.Builder builder = GroupContext.newBuilder()
.setId(ByteString.copyFrom(groupId))
.setType(GroupContext.Type.MODIFY);
boolean shouldSendUpdate = false;
final String title = groupName.getText().toString();
if (existingTitle == null || (groupName.getText() != null && !existingTitle.equals(title))) {
builder.setName(title);
db.updateTitle(groupId, title);
shouldSendUpdate = true;
}
byte[] avatarBytes = null;
if (existingAvatarBmp == null || !existingAvatarBmp.equals(avatarBmp)) {
if (avatarBmp != null) {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
avatarBmp.compress(Bitmap.CompressFormat.PNG, 100, stream);
avatarBytes = stream.toByteArray();
}
db.updateAvatar(groupId, avatarBytes);
shouldSendUpdate = true;
}
if (shouldSendUpdate) {
GroupContext context = builder.build();
OutgoingGroupMediaMessage outgoingMessage = new OutgoingGroupMediaMessage(this, groupRecipient, context, avatarBytes);
try {
MessageSender.send(this, masterSecret, outgoingMessage, groupThread);
} catch (MmsException me) {
Log.w(TAG, "MmsException encountered when trying to add members to group.", me);
}
}
RecipientFactory.clearCache(groupRecipient.getPrimaryRecipient());
setResult(RESULT_OK, getIntent());
finish();
}
private void enableWhisperGroupCreatingUi() {
findViewById(R.id.group_details_layout).setVisibility(View.GONE);
findViewById(R.id.creating_group_layout).setVisibility(View.VISIBLE);
@ -315,7 +424,12 @@ public class GroupCreateActivity extends PassphraseRequiredSherlockFragmentActiv
SelectedRecipientsAdapter adapter = (SelectedRecipientsAdapter)lv.getAdapter();
adapter.clear();
for (Recipient contact : selectedContacts) {
adapter.add(contact);
adapter.add(new SelectedRecipientsAdapter.RecipientWrapper(contact, true));
}
if (existingContacts != null) {
for (Recipient contact : existingContacts) {
adapter.add(new SelectedRecipientsAdapter.RecipientWrapper(contact, false));
}
}
adapter.notifyDataSetChanged();
}
@ -336,7 +450,8 @@ public class GroupCreateActivity extends PassphraseRequiredSherlockFragmentActiv
Recipient recipient = RecipientFactory.getRecipientsFromString(this, numberData.number, false)
.getPrimaryRecipient();
if (!selectedContacts.contains(recipient)) {
if (!selectedContacts.contains(recipient)
&& (existingContacts == null || !existingContacts.contains(recipient))) {
addSelectedContact(recipient);
}
} catch (RecipientFormattingException e) {
@ -347,14 +462,8 @@ public class GroupCreateActivity extends PassphraseRequiredSherlockFragmentActiv
syncAdapterWithSelectedContacts();
break;
case PICK_AVATAR:
if(resultCode == RESULT_OK) {
new DecodeCropAndSetAsyncTask().execute();
break;
} else {
Log.i(TAG, "Avatar selection result was not RESULT_OK.");
}
}
}
@ -411,6 +520,14 @@ public class GroupCreateActivity extends PassphraseRequiredSherlockFragmentActiv
ThreadDatabase.DistributionTypes.CONVERSATION);
}
private static <T> ArrayList<T> setToArrayList(Set<T> set) {
ArrayList<T> arrayList = new ArrayList<T>(set.size());
for (T item : set) {
arrayList.add(item);
}
return arrayList;
}
private List<String> getE164Numbers(Set<Recipient> recipients)
throws InvalidNumberException
{
@ -455,10 +572,7 @@ public class GroupCreateActivity extends PassphraseRequiredSherlockFragmentActiv
intent.putExtra(ConversationActivity.THREAD_ID_EXTRA, resultThread.longValue());
intent.putExtra(ConversationActivity.DISTRIBUTION_TYPE_EXTRA, ThreadDatabase.DistributionTypes.DEFAULT);
ArrayList<Recipient> selectedContactsList = new ArrayList<Recipient>(selectedContacts.size());
for (Recipient recipient : selectedContacts) {
selectedContactsList.add(recipient);
}
ArrayList<Recipient> selectedContactsList = setToArrayList(selectedContacts);
intent.putExtra(ConversationActivity.RECIPIENTS_EXTRA, new Recipients(selectedContactsList));
startActivity(intent);
finish();
@ -525,4 +639,58 @@ public class GroupCreateActivity extends PassphraseRequiredSherlockFragmentActiv
super.onProgressUpdate(values);
}
}
private class FillExistingGroupInfoAsyncTask extends AsyncTask<Void,Void,Boolean> {
@Override
protected void onPreExecute() {
pd = new ProgressDialog(GroupCreateActivity.this);
pd.setTitle("Loading group details...");
pd.setMessage("Please wait.");
pd.setCancelable(false);
pd.setIndeterminate(true);
pd.show();
}
@Override
protected Boolean doInBackground(Void... voids) {
final GroupDatabase db = DatabaseFactory.getGroupDatabase(GroupCreateActivity.this);
final Recipients recipients = db.getGroupMembers(groupId);
if (recipients != null) {
final List<Recipient> recipientList = recipients.getRecipientsList();
if (recipientList != null) {
if (existingContacts == null)
existingContacts = new HashSet<Recipient>(recipientList.size());
existingContacts.addAll(recipientList);
}
}
final GroupDatabase.Reader groupReader = db.getGroup(groupId);
GroupDatabase.GroupRecord group = groupReader.getNext();
if (group != null) {
existingTitle = group.getTitle();
final byte[] existingAvatar = group.getAvatar();
if (existingAvatar != null) {
existingAvatarBmp = BitmapUtil.getCircleCroppedBitmap(
BitmapFactory.decodeByteArray(existingAvatar, 0, existingAvatar.length));
}
return (group.getOwner() != null && group.getOwner().equals(TextSecurePreferences.getLocalNumber(GroupCreateActivity.this)));
}
return null;
}
@Override
protected void onPostExecute(Boolean isOwner) {
super.onPostExecute(isOwner);
if (pd != null) pd.dismiss();
if (existingTitle != null) groupName.setText(existingTitle);
if (existingAvatarBmp != null) avatar.setImageBitmap(existingAvatarBmp);
if (existingContacts != null) syncAdapterWithSelectedContacts();
if (!isOwner) {
disableWhisperGroupUi(R.string.GroupCreateActivity_you_dont_own_this_group);
getSupportActionBar().setTitle(getString(R.string.GroupCreateActivity_actionbar_update_title)
+ (TextUtils.isEmpty(existingTitle) ? "" : ": " + existingTitle));
}
}
}
}

View File

@ -9,6 +9,7 @@ import android.provider.ContactsContract;
import android.provider.ContactsContract.Contacts;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.util.LRUCache;
import java.io.InputStream;
@ -73,6 +74,11 @@ public class ContactPhotoFactory {
localUserContactPhotoCache.clear();
}
public static void clearCache(Recipient recipient) {
if (localUserContactPhotoCache.containsKey(recipient.getContactUri()))
localUserContactPhotoCache.remove(recipient.getContactUri());
}
private static Bitmap getContactPhoto(Context context, Uri uri) {
InputStream inputStream = ContactsContract.Contacts.openContactPhotoInputStream(context.getContentResolver(), uri);

View File

@ -4,6 +4,7 @@ package org.thoughtcrime.securesms.database;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.graphics.Bitmap;
import android.util.Log;
@ -21,6 +22,8 @@ import org.whispersystems.textsecure.util.Util;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
@ -138,6 +141,13 @@ public class GroupDatabase extends Database {
new String[] {GroupUtil.getEncodedId(groupId), source});
}
public void updateTitle(byte[] groupId, String title) {
ContentValues contentValues = new ContentValues();
contentValues.put(TITLE, title);
databaseHelper.getWritableDatabase().update(TABLE_NAME, contentValues, GROUP_ID + " = ?",
new String[] {GroupUtil.getEncodedId(groupId)});
}
public void updateAvatar(byte[] groupId, Bitmap avatar) {
updateAvatar(groupId, BitmapUtil.toByteArray(avatar));
}
@ -198,6 +208,28 @@ public class GroupDatabase extends Database {
}
}
public String getOwner(byte[] id) {
Cursor cursor = null;
try {
SQLiteDatabase readableDatabase = databaseHelper.getReadableDatabase();
if (readableDatabase == null)
return null;
cursor = databaseHelper.getReadableDatabase().query(TABLE_NAME, new String[] {OWNER},
GROUP_ID + " = ?",
new String[] {GroupUtil.getEncodedId(id)},
null, null, null);
if (cursor != null && cursor.moveToFirst()) {
return cursor.getString(cursor.getColumnIndexOrThrow(OWNER));
}
return null;
} finally {
if (cursor != null)
cursor.close();
}
}
public byte[] allocateGroupId() {
try {
byte[] groupId = new byte[16];
@ -224,6 +256,7 @@ public class GroupDatabase extends Database {
return new GroupRecord(cursor.getString(cursor.getColumnIndexOrThrow(GROUP_ID)),
cursor.getString(cursor.getColumnIndexOrThrow(TITLE)),
cursor.getString(cursor.getColumnIndexOrThrow(OWNER)),
cursor.getString(cursor.getColumnIndexOrThrow(MEMBERS)),
cursor.getBlob(cursor.getColumnIndexOrThrow(AVATAR)),
cursor.getLong(cursor.getColumnIndexOrThrow(AVATAR_ID)),
@ -242,6 +275,7 @@ public class GroupDatabase extends Database {
private final String id;
private final String title;
private final String owner;
private final List<String> members;
private final byte[] avatar;
private final long avatarId;
@ -249,12 +283,13 @@ public class GroupDatabase extends Database {
private final String avatarContentType;
private final String relay;
public GroupRecord(String id, String title, String members, byte[] avatar,
public GroupRecord(String id, String title, String owner, String members, byte[] avatar,
long avatarId, byte[] avatarKey, String avatarContentType,
String relay)
{
this.id = id;
this.title = title;
this.owner = owner;
this.members = Util.split(members, ",");
this.avatar = avatar;
this.avatarId = avatarId;
@ -275,6 +310,10 @@ public class GroupDatabase extends Database {
return title;
}
public String getOwner() {
return owner;
}
public List<String> getMembers() {
return members;
}

View File

@ -138,4 +138,9 @@ public class RecipientFactory {
provider.clearCache();
}
public static void clearCache(Recipient recipient) {
ContactPhotoFactory.clearCache(recipient);
provider.clearCache(recipient);
}
}

View File

@ -116,6 +116,11 @@ public class RecipientProvider {
recipientCache.clear();
}
public void clearCache(Recipient recipient) {
if (recipientCache.containsKey(recipient.getRecipientId()))
recipientCache.remove(recipient.getRecipientId());
}
private RecipientDetails getRecipientDetails(Context context, String number) {
Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number));
Cursor cursor = context.getContentResolver().query(uri, CALLER_ID_PROJECTION,

View File

@ -12,18 +12,17 @@ import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.recipients.Recipient;
import java.util.ArrayList;
import java.util.List;
public class SelectedRecipientsAdapter extends ArrayAdapter<Recipient> {
public class SelectedRecipientsAdapter extends ArrayAdapter<SelectedRecipientsAdapter.RecipientWrapper> {
private ArrayList<Recipient> recipients;
private ArrayList<RecipientWrapper> recipients;
private OnRecipientDeletedListener onRecipientDeletedListener;
public SelectedRecipientsAdapter(Context context, int textViewResourceId) {
super(context, textViewResourceId);
}
public SelectedRecipientsAdapter(Context context, int resource, ArrayList<Recipient> recipients) {
public SelectedRecipientsAdapter(Context context, int resource, ArrayList<RecipientWrapper> recipients) {
super(context, resource, recipients);
this.recipients = recipients;
}
@ -41,7 +40,9 @@ public class SelectedRecipientsAdapter extends ArrayAdapter<Recipient> {
}
Recipient p = getItem(position);
final RecipientWrapper rw = getItem(position);
final Recipient p = rw.getRecipient();
final boolean modifiable = rw.isModifiable();
if (p != null) {
@ -53,20 +54,25 @@ public class SelectedRecipientsAdapter extends ArrayAdapter<Recipient> {
name.setText(p.getName());
}
if (phone != null) {
phone.setText(p.getNumber());
}
if (delete != null) {
if (modifiable) {
delete.setVisibility(View.VISIBLE);
delete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (onRecipientDeletedListener != null) {
onRecipientDeletedListener.onRecipientDeleted(recipients.get(position));
onRecipientDeletedListener.onRecipientDeleted(recipients.get(position).getRecipient());
}
recipients.remove(position);
SelectedRecipientsAdapter.this.notifyDataSetChanged();
}
});
} else {
delete.setVisibility(View.INVISIBLE);
delete.setOnClickListener(null);
}
}
}
@ -80,4 +86,22 @@ public class SelectedRecipientsAdapter extends ArrayAdapter<Recipient> {
public interface OnRecipientDeletedListener {
public void onRecipientDeleted(Recipient recipient);
}
public static class RecipientWrapper {
private final Recipient recipient;
private final boolean modifiable;
public RecipientWrapper(final Recipient recipient, final boolean modifiable) {
this.recipient = recipient;
this.modifiable = modifiable;
}
public Recipient getRecipient() {
return recipient;
}
public boolean isModifiable() {
return modifiable;
}
}
}