session-android/src/org/thoughtcrime/securesms/GroupCreateActivity.java

408 lines
14 KiB
Java
Raw Normal View History

2014-01-19 02:17:08 +00:00
package org.thoughtcrime.securesms;
import android.app.Activity;
import android.content.Context;
2014-01-19 02:17:08 +00:00
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.AsyncTask;
2014-01-19 02:17:08 +00:00
import android.os.Bundle;
2014-02-12 20:05:18 +00:00
import android.text.Editable;
import android.text.TextWatcher;
2014-01-19 02:17:08 +00:00
import android.util.Log;
import android.view.View;
2014-02-12 20:05:18 +00:00
import android.widget.EditText;
import android.widget.ImageView;
2014-01-19 02:17:08 +00:00
import android.widget.ListView;
import android.widget.TextView;
2014-01-19 02:17:08 +00:00
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuInflater;
import com.actionbarsherlock.view.MenuItem;
2014-02-14 01:10:20 +00:00
import com.google.protobuf.ByteString;
2014-01-19 02:17:08 +00:00
import org.thoughtcrime.securesms.components.PushRecipientsPanel;
import org.thoughtcrime.securesms.contacts.ContactAccessor;
2014-02-14 01:10:20 +00:00
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.GroupDatabase;
import org.thoughtcrime.securesms.database.ThreadDatabase;
2014-01-19 02:17:08 +00:00
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientFactory;
import org.thoughtcrime.securesms.recipients.RecipientFormattingException;
2014-01-19 02:17:08 +00:00
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.sms.MessageSender;
2014-01-19 02:17:08 +00:00
import org.thoughtcrime.securesms.util.ActionBarUtil;
import org.thoughtcrime.securesms.util.DynamicLanguage;
import org.thoughtcrime.securesms.util.DynamicTheme;
2014-02-14 01:10:20 +00:00
import org.thoughtcrime.securesms.util.GroupUtil;
2014-01-19 02:17:08 +00:00
import org.thoughtcrime.securesms.util.SelectedRecipientsAdapter;
2014-02-14 01:10:20 +00:00
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Util;
2014-02-13 20:36:31 +00:00
import org.whispersystems.textsecure.crypto.MasterSecret;
import org.whispersystems.textsecure.directory.Directory;
import org.whispersystems.textsecure.directory.NotInDirectoryException;
import org.whispersystems.textsecure.util.Base64;
import org.whispersystems.textsecure.util.InvalidNumberException;
2014-01-19 02:17:08 +00:00
2014-02-13 20:15:26 +00:00
import java.io.ByteArrayOutputStream;
2014-02-14 01:10:20 +00:00
import java.io.IOException;
2014-01-19 02:17:08 +00:00
import java.util.ArrayList;
import java.util.Collection;
2014-01-19 02:17:08 +00:00
import java.util.HashSet;
2014-02-14 01:10:20 +00:00
import java.util.LinkedList;
2014-01-19 02:17:08 +00:00
import java.util.List;
import java.util.Set;
import ws.com.google.android.mms.MmsException;
import static org.thoughtcrime.securesms.contacts.ContactAccessor.ContactData;
2014-02-14 01:10:20 +00:00
import static org.whispersystems.textsecure.push.PushMessageProtos.PushMessageContent.GroupContext;
2014-01-19 02:17:08 +00:00
public class GroupCreateActivity extends PassphraseRequiredSherlockFragmentActivity {
private final static String TAG = "GroupCreateActivity";
2014-02-13 20:36:31 +00:00
public static final String MASTER_SECRET_EXTRA = "master_secret";
2014-01-19 02:17:08 +00:00
private final DynamicTheme dynamicTheme = new DynamicTheme();
private final DynamicLanguage dynamicLanguage = new DynamicLanguage();
private static final int PICK_CONTACT = 1;
private static final int PICK_AVATAR = 2;
2014-02-12 20:05:18 +00:00
private EditText groupName;
private ListView lv;
private PushRecipientsPanel recipientsPanel;
private ImageView avatar;
2014-01-19 02:17:08 +00:00
2014-02-13 20:36:31 +00:00
private MasterSecret masterSecret;
private Bitmap avatarBmp;
2014-02-13 20:15:26 +00:00
2014-01-19 02:17:08 +00:00
private Set<Recipient> selectedContacts;
@Override
public void onCreate(Bundle state) {
dynamicTheme.onCreate(this);
dynamicLanguage.onCreate(this);
super.onCreate(state);
setContentView(R.layout.group_create_activity);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
ActionBarUtil.initializeDefaultActionBar(this, getSupportActionBar(), R.string.GroupCreateActivity_actionbar_title);
2014-01-19 02:17:08 +00:00
selectedContacts = new HashSet<Recipient>();
initializeResources();
}
@Override
public void onResume() {
super.onResume();
dynamicTheme.onResume(this);
}
2014-02-13 20:15:26 +00:00
private boolean whisperGroupUiEnabled() {
return groupName.isEnabled() && avatar.isEnabled();
}
private void disableWhisperGroupUi() {
View pushDisabled = findViewById(R.id.push_disabled);
pushDisabled.setVisibility(View.VISIBLE);
avatar.setEnabled(false);
groupName.setEnabled(false);
getSupportActionBar().setTitle(R.string.GroupCreateActivity_actionbar_mms_title);
}
2014-02-13 20:15:26 +00:00
private void enableWhisperGroupUi() {
findViewById(R.id.push_disabled).setVisibility(View.GONE);
avatar.setEnabled(true);
groupName.setEnabled(true);
final CharSequence groupNameText = groupName.getText();
if (groupNameText.length() > 0)
getSupportActionBar().setTitle(groupNameText);
else
getSupportActionBar().setTitle(R.string.GroupCreateActivity_actionbar_title);
}
private static boolean isActiveInDirectory(Context context, Recipient recipient) {
try {
if (!Directory.getInstance(context).isActiveNumber(Util.canonicalizeNumber(context, recipient.getNumber()))) {
return false;
}
} catch (NotInDirectoryException e) {
return false;
2014-02-13 20:36:31 +00:00
} catch (InvalidNumberException e) {
return false;
}
return true;
}
private void addSelectedContact(Recipient contact) {
selectedContacts.add(contact);
2014-02-13 20:15:26 +00:00
if (!isActiveInDirectory(this, contact)) disableWhisperGroupUi();
}
private void addAllSelectedContacts(Collection<Recipient> contacts) {
for (Recipient contact : contacts) {
addSelectedContact(contact);
}
}
private void removeSelectedContact(Recipient contact) {
Log.i(TAG, "remoevSelectedContact: " + contact.getName() + "/" + contact.getNumber());
selectedContacts.remove(contact);
if (!isActiveInDirectory(this, contact)) {
for (Recipient recipient : selectedContacts) {
if (!isActiveInDirectory(this, recipient))
return;
}
2014-02-13 20:15:26 +00:00
enableWhisperGroupUi();
}
}
2014-01-19 02:17:08 +00:00
private void initializeResources() {
2014-02-13 20:36:31 +00:00
masterSecret = getIntent().getParcelableExtra(MASTER_SECRET_EXTRA);
2014-02-12 20:05:18 +00:00
groupName = (EditText) findViewById(R.id.group_name);
groupName.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) { }
@Override
public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) { }
@Override
public void afterTextChanged(Editable editable) {
if (editable.length() > 0)
2014-02-13 09:35:08 +00:00
getSupportActionBar().setTitle(getString(R.string.GroupCreateActivity_actionbar_title) + ": " + editable.toString());
2014-02-12 20:05:18 +00:00
else
getSupportActionBar().setTitle(R.string.GroupCreateActivity_actionbar_title);
2014-02-12 20:05:18 +00:00
}
});
2014-01-19 02:17:08 +00:00
lv = (ListView) findViewById(R.id.selected_contacts_list);
SelectedRecipientsAdapter adapter = new SelectedRecipientsAdapter(this, android.R.id.text1, new ArrayList<Recipient>());
adapter.setOnRecipientDeletedListener(new SelectedRecipientsAdapter.OnRecipientDeletedListener() {
@Override
public void onRecipientDeleted(Recipient recipient) {
removeSelectedContact(recipient);
}
});
lv.setAdapter(adapter);
recipientsPanel = (PushRecipientsPanel) findViewById(R.id.recipients);
recipientsPanel.setPanelChangeListener(new PushRecipientsPanel.RecipientsPanelChangedListener() {
@Override
public void onRecipientsPanelUpdate(Recipients recipients) {
Log.i(TAG, "onRecipientsPanelUpdate received.");
if (recipients != null) {
addAllSelectedContacts(recipients.getRecipientsList());
syncAdapterWithSelectedContacts();
}
}
});
(findViewById(R.id.contacts_button)).setOnClickListener(new AddRecipientButtonListener());
avatar = (ImageView) findViewById(R.id.avatar);
avatar.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent photoPickerIntent = new Intent(Intent.ACTION_GET_CONTENT, null);
photoPickerIntent.setType("image/*");
photoPickerIntent.putExtra("crop", "true");
photoPickerIntent.putExtra("aspectX", 1);
photoPickerIntent.putExtra("aspectY", 1);
photoPickerIntent.putExtra("outputX", 210);
photoPickerIntent.putExtra("outputY", 210);
photoPickerIntent.putExtra("return-data", "true");
startActivityForResult(photoPickerIntent, PICK_AVATAR);
}
});
2014-01-19 02:17:08 +00:00
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
MenuInflater inflater = this.getSupportMenuInflater();
menu.clear();
inflater.inflate(R.menu.group_create, menu);
super.onPrepareOptionsMenu(menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
super.onOptionsItemSelected(item);
switch (item.getItemId()) {
case android.R.id.home:
finish();
return true;
2014-01-19 02:17:08 +00:00
case R.id.menu_create_group:
2014-02-13 20:15:26 +00:00
if (whisperGroupUiEnabled()) {
findViewById(R.id.group_details_layout).setVisibility(View.GONE);
findViewById(R.id.creating_group_layout).setVisibility(View.VISIBLE);
findViewById(R.id.menu_create_group).setVisibility(View.GONE);
((TextView)findViewById(R.id.creating_group_text)).setText("Creating " + groupName.getText().toString() + "...");
new AsyncTask<Void,Void,Void>() {
@Override
protected Void doInBackground(Void... voids) {
byte[] byteArray = null;
if (avatarBmp != null) {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
avatarBmp.compress(Bitmap.CompressFormat.PNG, 100, stream);
byteArray = stream.toByteArray();
}
2014-02-14 01:10:20 +00:00
try {
handleCreatePushGroup(groupName.getText().toString(), byteArray, selectedContacts);
} catch (IOException e) {
// TODO Jake's gonna fill this in.
Log.w("GroupCreateActivity", e);
} catch (InvalidNumberException e) {
// TODO jake's gonna fill this in.
Log.w("GroupCreateActivity", e);
}
2014-02-13 20:15:26 +00:00
return null;
}
2014-02-13 20:15:26 +00:00
@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
finish();
}
2014-02-13 20:15:26 +00:00
@Override
protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values);
}
}.execute();
} else {
new AsyncTask<Void,Void,Void>() {
@Override
protected Void doInBackground(Void... voids) {
handleCreateMmsGroup(selectedContacts);
return null;
}
2014-02-13 20:15:26 +00:00
@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
finish();
}
@Override
protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values);
}
}.execute();
}
2014-01-19 02:17:08 +00:00
return true;
}
return false;
}
private void syncAdapterWithSelectedContacts() {
SelectedRecipientsAdapter adapter = (SelectedRecipientsAdapter)lv.getAdapter();
adapter.clear();
for (Recipient contact : selectedContacts) {
adapter.add(contact);
}
adapter.notifyDataSetChanged();
}
2014-01-19 02:17:08 +00:00
@Override
public void onActivityResult(int reqCode, int resultCode, Intent data) {
Log.w("ComposeMessageActivity", "onActivityResult called: " + resultCode + " , " + data);
super.onActivityResult(reqCode, resultCode, data);
if (data == null || resultCode != Activity.RESULT_OK)
return;
switch (reqCode) {
case PICK_CONTACT:
List<ContactData> selected = data.getParcelableArrayListExtra("contacts");
for (ContactData contact : selected) {
for (ContactAccessor.NumberData numberData : contact.numbers) {
try {
Recipient recipient = RecipientFactory.getRecipientsFromString(this, numberData.number, false)
.getPrimaryRecipient();
if (!selectedContacts.contains(recipient)) {
addSelectedContact(recipient);
}
} catch (RecipientFormattingException e) {
Log.w("GroupCreateActivity", e);
}
2014-01-19 02:17:08 +00:00
}
}
syncAdapterWithSelectedContacts();
2014-01-19 02:17:08 +00:00
break;
case PICK_AVATAR:
if(resultCode == RESULT_OK) {
2014-02-13 20:15:26 +00:00
avatarBmp = data.getParcelableExtra("data");
avatar.setImageBitmap(avatarBmp);
//Uri selectedImage = data.getData();
//avatar.setImageURI(selectedImage);
2014-01-19 02:17:08 +00:00
break;
}
}
}
private class AddRecipientButtonListener implements View.OnClickListener {
@Override
public void onClick(View v) {
Intent intent = new Intent(GroupCreateActivity.this, PushContactSelectionActivity.class);
startActivityForResult(intent, PICK_CONTACT);
}
}
2014-02-13 20:15:26 +00:00
private long handleCreatePushGroup(String groupName,
byte[] avatar,
Set<Recipient> members)
throws InvalidNumberException, MmsException
2014-02-14 01:10:20 +00:00
{
GroupDatabase groupDatabase = DatabaseFactory.getGroupDatabase(this);
byte[] groupId = groupDatabase.allocateGroupId();
try {
List<String> memberE164Numbers = getE164Numbers(members);
String groupRecipientId = GroupUtil.getEncodedId(groupId);
2014-02-14 01:10:20 +00:00
String groupActionArguments = GroupUtil.serializeArguments(groupId, groupName, memberE164Numbers);
2014-02-14 01:10:20 +00:00
groupDatabase.create(groupId, TextSecurePreferences.getLocalNumber(this), groupName,
memberE164Numbers, null, null);
2014-02-14 01:10:20 +00:00
groupDatabase.updateAvatar(groupId, avatar);
Recipients groupRecipient = RecipientFactory.getRecipientsFromString(this, groupRecipientId, false);
return MessageSender.sendGroupAction(this, masterSecret, groupRecipient, -1,
GroupContext.Type.CREATE_VALUE,
groupActionArguments, avatar);
} catch (RecipientFormattingException e) {
throw new AssertionError(e);
} catch (MmsException e) {
Log.w("GroupCreateActivity", e);
groupDatabase.remove(groupId, TextSecurePreferences.getLocalNumber(this));
throw new MmsException(e);
}
2014-02-14 01:10:20 +00:00
}
private long handleCreateMmsGroup(Set<Recipient> members) {
Recipients recipients = new Recipients(new LinkedList<Recipient>(members));
return DatabaseFactory.getThreadDatabase(this)
.getThreadIdFor(recipients,
ThreadDatabase.DistributionTypes.CONVERSATION);
2014-02-13 20:15:26 +00:00
}
2014-02-14 01:10:20 +00:00
private List<String> getE164Numbers(Set<Recipient> recipients)
throws InvalidNumberException
{
List<String> results = new LinkedList<String>();
for (Recipient recipient : recipients) {
results.add(Util.canonicalizeNumber(this, recipient.getNumber()));
}
return results;
2014-02-13 20:15:26 +00:00
}
2014-01-19 02:17:08 +00:00
}