diff options
Diffstat (limited to 'src/eu/siacs/conversations/ui')
16 files changed, 670 insertions, 417 deletions
diff --git a/src/eu/siacs/conversations/ui/ChooseContactActivity.java b/src/eu/siacs/conversations/ui/ChooseContactActivity.java index 4236ea703..277d21d6a 100644 --- a/src/eu/siacs/conversations/ui/ChooseContactActivity.java +++ b/src/eu/siacs/conversations/ui/ChooseContactActivity.java @@ -23,13 +23,13 @@ import eu.siacs.conversations.entities.ListItem; import eu.siacs.conversations.ui.adapter.ListItemAdapter; public class ChooseContactActivity extends XmppActivity { - + private ListView mListView; private ArrayList<ListItem> contacts = new ArrayList<ListItem>(); private ArrayAdapter<ListItem> mContactsAdapter; - + private EditText mSearchEditText; - + private TextWatcher mSearchTextWatcher = new TextWatcher() { @Override @@ -47,7 +47,7 @@ public class ChooseContactActivity extends XmppActivity { int count) { } }; - + private MenuItem.OnActionExpandListener mOnActionExpandListener = new MenuItem.OnActionExpandListener() { @Override @@ -76,35 +76,39 @@ public class ChooseContactActivity extends XmppActivity { return true; } }; - - - + @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_choose_contact); mListView = (ListView) findViewById(R.id.choose_contact_list); - mContactsAdapter = new ListItemAdapter(getApplicationContext(), contacts); + mContactsAdapter = new ListItemAdapter(this, contacts); mListView.setAdapter(mContactsAdapter); mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override - public void onItemClick(AdapterView<?> arg0, View arg1, int position, - long arg3) { + public void onItemClick(AdapterView<?> arg0, View arg1, + int position, long arg3) { InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(mSearchEditText.getWindowToken(), InputMethodManager.HIDE_IMPLICIT_ONLY); Intent request = getIntent(); Intent data = new Intent(); - data.putExtra("contact",contacts.get(position).getJid()); - data.putExtra("account",request.getStringExtra("account")); - data.putExtra("conversation",request.getStringExtra("conversation")); + ListItem mListItem = contacts.get(position); + data.putExtra("contact", mListItem.getJid()); + String account = request.getStringExtra("account"); + if (account == null && mListItem instanceof Contact) { + account = ((Contact) mListItem).getAccount().getJid(); + } + data.putExtra("account", account); + data.putExtra("conversation", + request.getStringExtra("conversation")); setResult(RESULT_OK, data); finish(); } }); } - + @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.choose_contact, menu); @@ -121,7 +125,7 @@ public class ChooseContactActivity extends XmppActivity { void onBackendConnected() { filterContacts(null); } - + protected void filterContacts(String needle) { this.contacts.clear(); for (Account account : xmppConnectionService.getAccounts()) { diff --git a/src/eu/siacs/conversations/ui/ConferenceDetailsActivity.java b/src/eu/siacs/conversations/ui/ConferenceDetailsActivity.java index c33277f94..2cfa16357 100644 --- a/src/eu/siacs/conversations/ui/ConferenceDetailsActivity.java +++ b/src/eu/siacs/conversations/ui/ConferenceDetailsActivity.java @@ -109,7 +109,7 @@ public class ConferenceDetailsActivity extends XmppActivity { break; case R.id.action_edit_subject: if (conversation != null) { - quickEdit(conversation.getName(true), new OnValueEdited() { + quickEdit(conversation.getName(), new OnValueEdited() { @Override public void onValueEdited(String value) { @@ -200,7 +200,7 @@ public class ConferenceDetailsActivity extends XmppActivity { private void populateView() { mYourPhoto.setImageBitmap(conversation.getAccount().getImage(this, 48)); - setTitle(conversation.getName(true)); + setTitle(conversation.getName()); mFullJid.setText(conversation.getContactJid().split("/")[0]); mYourNick.setText(conversation.getMucOptions().getActualNick()); mRoleAffiliaton = (TextView) findViewById(R.id.muc_role); @@ -250,7 +250,8 @@ public class ConferenceDetailsActivity extends XmppActivity { if (contact.showInRoster()) { bm = contact.getImage(48, this); name.setText(contact.getDisplayName()); - role.setText(user.getName() + " \u2022 " + getReadableRole(user.getRole())); + role.setText(user.getName() + " \u2022 " + + getReadableRole(user.getRole())); } else { bm = UIHelper.getContactPicture(user.getName(), 48, this, false); diff --git a/src/eu/siacs/conversations/ui/ContactDetailsActivity.java b/src/eu/siacs/conversations/ui/ContactDetailsActivity.java index 7c13c5185..8de2ce804 100644 --- a/src/eu/siacs/conversations/ui/ContactDetailsActivity.java +++ b/src/eu/siacs/conversations/ui/ContactDetailsActivity.java @@ -23,6 +23,7 @@ import android.view.View.OnClickListener; import android.widget.CheckBox; import android.widget.CompoundButton.OnCheckedChangeListener; import android.widget.CompoundButton; +import android.widget.ImageButton; import android.widget.LinearLayout; import android.widget.QuickContactBadge; import android.widget.TextView; @@ -111,7 +112,8 @@ public class ContactDetailsActivity extends XmppActivity { public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { if (isChecked) { - if (contact.getOption(Contact.Options.PENDING_SUBSCRIPTION_REQUEST)) { + if (contact + .getOption(Contact.Options.PENDING_SUBSCRIPTION_REQUEST)) { xmppConnectionService.sendPresencePacket(contact .getAccount(), xmppConnectionService.getPresenceGenerator() @@ -146,7 +148,7 @@ public class ContactDetailsActivity extends XmppActivity { }; private OnAccountUpdate accountUpdate = new OnAccountUpdate() { - + @Override public void onAccountUpdate() { runOnUiThread(new Runnable() { @@ -269,7 +271,7 @@ public class ContactDetailsActivity extends XmppActivity { send.setOnCheckedChangeListener(this.mOnSendCheckedChange); receive.setOnCheckedChangeListener(this.mOnReceiveCheckedChange); - + lastseen.setText(UIHelper.lastseen(getApplicationContext(), contact.lastseen.time)); @@ -322,16 +324,28 @@ public class ContactDetailsActivity extends XmppActivity { LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); for (Iterator<String> iterator = contact.getOtrFingerprints() .iterator(); iterator.hasNext();) { - String otrFingerprint = iterator.next(); - View view = (View) inflater.inflate(R.layout.contact_key, null); + final String otrFingerprint = iterator.next(); + View view = (View) inflater.inflate(R.layout.contact_key, keys, + false); TextView key = (TextView) view.findViewById(R.id.key); TextView keyType = (TextView) view.findViewById(R.id.key_type); + ImageButton remove = (ImageButton) view + .findViewById(R.id.button_remove); + remove.setVisibility(View.VISIBLE); keyType.setText("OTR Fingerprint"); key.setText(otrFingerprint); keys.addView(view); + remove.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + confirmToDeleteFingerprint(otrFingerprint); + } + }); } if (contact.getPgpKeyId() != 0) { - View view = (View) inflater.inflate(R.layout.contact_key, null); + View view = (View) inflater.inflate(R.layout.contact_key, keys, + false); TextView key = (TextView) view.findViewById(R.id.key); TextView keyType = (TextView) view.findViewById(R.id.key_type); keyType.setText("PGP Key ID"); @@ -360,10 +374,32 @@ public class ContactDetailsActivity extends XmppActivity { } } + protected void confirmToDeleteFingerprint(final String fingerprint) { + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle(R.string.delete_fingerprint); + builder.setMessage(R.string.sure_delete_fingerprint); + builder.setNegativeButton(R.string.cancel, null); + builder.setPositiveButton(R.string.delete, + new android.content.DialogInterface.OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int which) { + if (contact.deleteOtrFingerprint(fingerprint)) { + populateView(); + xmppConnectionService.syncRosterToDisk(contact + .getAccount()); + } + } + + }); + builder.create().show(); + } + @Override public void onBackendConnected() { xmppConnectionService.setOnRosterUpdateListener(this.rosterUpdate); - xmppConnectionService.setOnAccountListChangedListener(this.accountUpdate ); + xmppConnectionService + .setOnAccountListChangedListener(this.accountUpdate); if ((accountJid != null) && (contactJid != null)) { Account account = xmppConnectionService .findAccountByJid(accountJid); diff --git a/src/eu/siacs/conversations/ui/ConversationActivity.java b/src/eu/siacs/conversations/ui/ConversationActivity.java index c68063d23..5eedda1c7 100644 --- a/src/eu/siacs/conversations/ui/ConversationActivity.java +++ b/src/eu/siacs/conversations/ui/ConversationActivity.java @@ -1,10 +1,7 @@ package eu.siacs.conversations.ui; -import java.io.FileNotFoundException; -import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.RejectedExecutionException; import eu.siacs.conversations.R; import eu.siacs.conversations.entities.Contact; @@ -15,8 +12,8 @@ import eu.siacs.conversations.ui.adapter.ConversationAdapter; import eu.siacs.conversations.utils.ExceptionHelper; import eu.siacs.conversations.utils.UIHelper; import android.net.Uri; -import android.os.AsyncTask; import android.os.Bundle; +import android.os.SystemClock; import android.preference.PreferenceManager; import android.provider.MediaStore; import android.app.ActionBar; @@ -27,15 +24,8 @@ import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; import android.content.IntentSender.SendIntentException; import android.content.Intent; -import android.content.SharedPreferences; -import android.content.res.Resources; -import android.graphics.Bitmap; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.Drawable; import android.support.v4.widget.SlidingPaneLayout; import android.support.v4.widget.SlidingPaneLayout.PanelSlideListener; -import android.util.DisplayMetrics; -import android.util.Log; import android.view.KeyEvent; import android.view.Menu; import android.view.MenuItem; @@ -47,7 +37,6 @@ import android.widget.CheckBox; import android.widget.ListView; import android.widget.PopupMenu; import android.widget.PopupMenu.OnMenuItemClickListener; -import android.widget.ImageView; import android.widget.Toast; public class ConversationActivity extends XmppActivity { @@ -76,12 +65,10 @@ public class ConversationActivity extends XmppActivity { private ListView listView; private boolean paneShouldBeOpen = true; - private boolean useSubject = true; - private boolean showLastseen = false; private ArrayAdapter<Conversation> listAdapter; private OnConversationUpdate onConvChanged = new OnConversationUpdate() { - + @Override public void onConversationUpdate() { runOnUiThread(new Runnable() { @@ -109,9 +96,8 @@ public class ConversationActivity extends XmppActivity { }; protected ConversationActivity activity = this; - private DisplayMetrics metrics; private Toast prepareImageToast; - + private Uri pendingImageUri = null; public List<Conversation> getConversationList() { @@ -140,15 +126,12 @@ public class ConversationActivity extends XmppActivity { @Override protected void onCreate(Bundle savedInstanceState) { - - metrics = getResources().getDisplayMetrics(); - super.onCreate(savedInstanceState); setContentView(R.layout.fragment_conversations_overview); listView = (ListView) findViewById(R.id.list); - + getActionBar().setDisplayHomeAsUpEnabled(false); getActionBar().setHomeButtonEnabled(false); @@ -179,7 +162,7 @@ public class ConversationActivity extends XmppActivity { public void onPanelOpened(View arg0) { paneShouldBeOpen = true; ActionBar ab = getActionBar(); - if (ab!=null) { + if (ab != null) { ab.setDisplayHomeAsUpEnabled(false); ab.setHomeButtonEnabled(false); ab.setTitle(R.string.app_name); @@ -194,11 +177,10 @@ public class ConversationActivity extends XmppActivity { if ((conversationList.size() > 0) && (getSelectedConversation() != null)) { ActionBar ab = getActionBar(); - if (ab!=null) { + if (ab != null) { ab.setDisplayHomeAsUpEnabled(true); ab.setHomeButtonEnabled(true); - ab.setTitle( - getSelectedConversation().getName(useSubject)); + ab.setTitle(getSelectedConversation().getName()); } invalidateOptionsMenu(); if (!getSelectedConversation().isRead()) { @@ -232,7 +214,9 @@ public class ConversationActivity extends XmppActivity { MenuItem menuClearHistory = (MenuItem) menu .findItem(R.id.action_clear_history); MenuItem menuAdd = (MenuItem) menu.findItem(R.id.action_add); - MenuItem menuInviteContact = (MenuItem) menu.findItem(R.id.action_invite); + MenuItem menuInviteContact = (MenuItem) menu + .findItem(R.id.action_invite); + MenuItem menuMute = (MenuItem) menu.findItem(R.id.action_mute); if ((spl.isOpen() && (spl.isSlideable()))) { menuArchive.setVisible(false); @@ -242,6 +226,7 @@ public class ConversationActivity extends XmppActivity { menuInviteContact.setVisible(false); menuAttach.setVisible(false); menuClearHistory.setVisible(false); + menuMute.setVisible(false); } else { menuAdd.setVisible(!spl.isSlideable()); if (this.getSelectedConversation() != null) { @@ -267,11 +252,12 @@ public class ConversationActivity extends XmppActivity { @Override public void onPresenceSelected() { if (attachmentChoice == ATTACHMENT_CHOICE_TAKE_PHOTO) { - pendingImageUri = xmppConnectionService.getFileBackend().getTakePhotoUri(); - Log.d("xmppService",pendingImageUri.toString()); + pendingImageUri = xmppConnectionService.getFileBackend() + .getTakePhotoUri(); Intent takePictureIntent = new Intent( MediaStore.ACTION_IMAGE_CAPTURE); - takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT,pendingImageUri); + takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, + pendingImageUri); if (takePictureIntent.resolveActivity(getPackageManager()) != null) { startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE); @@ -294,7 +280,7 @@ public class ConversationActivity extends XmppActivity { private void attachFile(final int attachmentChoice) { final Conversation conversation = getSelectedConversation(); - if (conversation.getNextEncryption() == Message.ENCRYPTION_PGP) { + if (conversation.getNextEncryption(forceEncryption()) == Message.ENCRYPTION_PGP) { if (hasPgp()) { if (conversation.getContact().getPgpKeyId() != 0) { xmppConnectionService.getPgpEngine().hasKey( @@ -338,7 +324,8 @@ public class ConversationActivity extends XmppActivity { } else { showInstallPgpDialog(); } - } else if (getSelectedConversation().getNextEncryption() == Message.ENCRYPTION_NONE) { + } else if (getSelectedConversation().getNextEncryption( + forceEncryption()) == Message.ENCRYPTION_NONE) { selectPresenceToAttachFile(attachmentChoice); } else { selectPresenceToAttachFile(attachmentChoice); @@ -353,7 +340,7 @@ public class ConversationActivity extends XmppActivity { return true; case R.id.action_attach_file: View menuAttachFile = findViewById(R.id.action_attach_file); - if (menuAttachFile==null) { + if (menuAttachFile == null) { break; } PopupMenu attachFilePopup = new PopupMenu(this, menuAttachFile); @@ -405,7 +392,7 @@ public class ConversationActivity extends XmppActivity { case R.id.action_security: final Conversation conversation = getSelectedConversation(); View menuItemView = findViewById(R.id.action_security); - if (menuItemView==null) { + if (menuItemView == null) { break; } PopupMenu popup = new PopupMenu(this, menuItemView); @@ -454,13 +441,18 @@ public class ConversationActivity extends XmppActivity { popup.inflate(R.menu.encryption_choices); MenuItem otr = popup.getMenu().findItem( R.id.encryption_choice_otr); + MenuItem none = popup.getMenu().findItem( + R.id.encryption_choice_none); if (conversation.getMode() == Conversation.MODE_MULTI) { otr.setEnabled(false); + } else { + if (forceEncryption()) { + none.setVisible(false); + } } - switch (conversation.getNextEncryption()) { + switch (conversation.getNextEncryption(forceEncryption())) { case Message.ENCRYPTION_NONE: - popup.getMenu().findItem(R.id.encryption_choice_none) - .setChecked(true); + none.setChecked(true); break; case Message.ENCRYPTION_OTR: otr.setChecked(true); @@ -481,6 +473,9 @@ public class ConversationActivity extends XmppActivity { case R.id.action_clear_history: clearHistoryDialog(getSelectedConversation()); break; + case R.id.action_mute: + muteConversationDialog(getSelectedConversation()); + break; default: break; } @@ -523,15 +518,43 @@ public class ConversationActivity extends XmppActivity { builder.create().show(); } + protected void muteConversationDialog(final Conversation conversation) { + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle(R.string.disable_notifications_for_this_conversation); + final int[] durations = getResources().getIntArray( + R.array.mute_options_durations); + builder.setItems(R.array.mute_options_descriptions, + new OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int which) { + long till; + if (durations[which] == -1) { + till = Long.MAX_VALUE; + } else { + till = SystemClock.elapsedRealtime() + + (durations[which] * 1000); + } + conversation.setMutedTill(till); + ConversationFragment selectedFragment = (ConversationFragment) getFragmentManager() + .findFragmentByTag("conversation"); + if (selectedFragment != null) { + selectedFragment.updateMessages(); + } + } + }); + builder.create().show(); + } + protected ConversationFragment swapConversationFragment() { ConversationFragment selectedFragment = new ConversationFragment(); if (!isFinishing()) { - FragmentTransaction transaction = getFragmentManager() - .beginTransaction(); - transaction.replace(R.id.selected_conversation, selectedFragment, - "conversation"); - + FragmentTransaction transaction = getFragmentManager() + .beginTransaction(); + transaction.replace(R.id.selected_conversation, selectedFragment, + "conversation"); + transaction.commitAllowingStateLoss(); } return selectedFragment; @@ -553,7 +576,8 @@ public class ConversationActivity extends XmppActivity { if (xmppConnectionServiceBound) { if ((Intent.ACTION_VIEW.equals(intent.getAction()) && (VIEW_CONVERSATION .equals(intent.getType())))) { - String convToView = (String) intent.getExtras().get(CONVERSATION); + String convToView = (String) intent.getExtras().get( + CONVERSATION); updateConversationList(); for (int i = 0; i < conversationList.size(); ++i) { if (conversationList.get(i).getUuid().equals(convToView)) { @@ -574,10 +598,6 @@ public class ConversationActivity extends XmppActivity { @Override public void onStart() { super.onStart(); - SharedPreferences preferences = PreferenceManager - .getDefaultSharedPreferences(this); - this.useSubject = preferences.getBoolean("use_subject_in_muc", true); - this.showLastseen = preferences.getBoolean("show_last_seen", false); if (this.xmppConnectionServiceBound) { this.onBackendConnected(); } @@ -600,9 +620,10 @@ public class ConversationActivity extends XmppActivity { if (conversationList.size() == 0) { updateConversationList(); } - - if (getSelectedConversation()!=null && pendingImageUri !=null) { - attachImageToConversation(getSelectedConversation(), pendingImageUri); + + if (getSelectedConversation() != null && pendingImageUri != null) { + attachImageToConversation(getSelectedConversation(), + pendingImageUri); pendingImageUri = null; } else { pendingImageUri = null; @@ -670,7 +691,8 @@ public class ConversationActivity extends XmppActivity { } else if (requestCode == REQUEST_ATTACH_FILE_DIALOG) { pendingImageUri = data.getData(); if (xmppConnectionServiceBound) { - attachImageToConversation(getSelectedConversation(),pendingImageUri); + attachImageToConversation(getSelectedConversation(), + pendingImageUri); pendingImageUri = null; } } else if (requestCode == REQUEST_SEND_PGP_IMAGE) { @@ -686,10 +708,12 @@ public class ConversationActivity extends XmppActivity { // encryptTextMessage(); } else if (requestCode == REQUEST_IMAGE_CAPTURE) { if (xmppConnectionServiceBound) { - attachImageToConversation(getSelectedConversation(), pendingImageUri); + attachImageToConversation(getSelectedConversation(), + pendingImageUri); pendingImageUri = null; } - Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE); + Intent intent = new Intent( + Intent.ACTION_MEDIA_SCANNER_SCAN_FILE); intent.setData(pendingImageUri); sendBroadcast(intent); } else if (requestCode == REQUEST_RECORD_AUDIO) { @@ -700,7 +724,7 @@ public class ConversationActivity extends XmppActivity { } private void attachAudioToConversation(Conversation conversation, Uri uri) { - + } private void attachImageToConversation(Conversation conversation, Uri uri) { @@ -744,122 +768,16 @@ public class ConversationActivity extends XmppActivity { } public void updateConversationList() { - xmppConnectionService.populateWithOrderedConversations(conversationList); - listView.invalidateViews(); - } - - public boolean showLastseen() { - if (getSelectedConversation() == null) { - return false; - } else { - return this.showLastseen - && getSelectedConversation().getMode() == Conversation.MODE_SINGLE; - } + xmppConnectionService + .populateWithOrderedConversations(conversationList); + listAdapter.notifyDataSetChanged(); } public void runIntent(PendingIntent pi, int requestCode) { try { this.startIntentSenderForResult(pi.getIntentSender(), requestCode, null, 0, 0, 0); - } catch (SendIntentException e1) {} - } - - class BitmapWorkerTask extends AsyncTask<Message, Void, Bitmap> { - private final WeakReference<ImageView> imageViewReference; - private Message message = null; - - public BitmapWorkerTask(ImageView imageView) { - imageViewReference = new WeakReference<ImageView>(imageView); - } - - @Override - protected Bitmap doInBackground(Message... params) { - message = params[0]; - try { - return xmppConnectionService.getFileBackend().getThumbnail( - message, (int) (metrics.density * 288), false); - } catch (FileNotFoundException e) { - return null; - } - } - - @Override - protected void onPostExecute(Bitmap bitmap) { - if (imageViewReference != null && bitmap != null) { - final ImageView imageView = imageViewReference.get(); - if (imageView != null) { - imageView.setImageBitmap(bitmap); - imageView.setBackgroundColor(0x00000000); - } - } - } - } - - public void loadBitmap(Message message, ImageView imageView) { - Bitmap bm; - try { - bm = xmppConnectionService.getFileBackend().getThumbnail(message, - (int) (metrics.density * 288), true); - } catch (FileNotFoundException e) { - bm = null; - } - if (bm != null) { - imageView.setImageBitmap(bm); - imageView.setBackgroundColor(0x00000000); - } else { - if (cancelPotentialWork(message, imageView)) { - imageView.setBackgroundColor(0xff333333); - final BitmapWorkerTask task = new BitmapWorkerTask(imageView); - final AsyncDrawable asyncDrawable = new AsyncDrawable( - getResources(), null, task); - imageView.setImageDrawable(asyncDrawable); - try { - task.execute(message); - } catch (RejectedExecutionException e) { - return; - } - } - } - } - - public static boolean cancelPotentialWork(Message message, - ImageView imageView) { - final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView); - - if (bitmapWorkerTask != null) { - final Message oldMessage = bitmapWorkerTask.message; - if (oldMessage == null || message != oldMessage) { - bitmapWorkerTask.cancel(true); - } else { - return false; - } - } - return true; - } - - private static BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) { - if (imageView != null) { - final Drawable drawable = imageView.getDrawable(); - if (drawable instanceof AsyncDrawable) { - final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable; - return asyncDrawable.getBitmapWorkerTask(); - } - } - return null; - } - - static class AsyncDrawable extends BitmapDrawable { - private final WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference; - - public AsyncDrawable(Resources res, Bitmap bitmap, - BitmapWorkerTask bitmapWorkerTask) { - super(res, bitmap); - bitmapWorkerTaskReference = new WeakReference<BitmapWorkerTask>( - bitmapWorkerTask); - } - - public BitmapWorkerTask getBitmapWorkerTask() { - return bitmapWorkerTaskReference.get(); + } catch (SendIntentException e1) { } } @@ -886,4 +804,9 @@ public class ConversationActivity extends XmppActivity { } }); } + + public boolean forceEncryption() { + return PreferenceManager.getDefaultSharedPreferences( + getApplicationContext()).getBoolean("force_encryption", false); + } } diff --git a/src/eu/siacs/conversations/ui/ConversationFragment.java b/src/eu/siacs/conversations/ui/ConversationFragment.java index 9309db9cf..b73bcadbe 100644 --- a/src/eu/siacs/conversations/ui/ConversationFragment.java +++ b/src/eu/siacs/conversations/ui/ConversationFragment.java @@ -15,6 +15,7 @@ import eu.siacs.conversations.entities.MucOptions; import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.ui.EditMessage.OnEnterPressed; import eu.siacs.conversations.ui.XmppActivity.OnPresenceSelected; +import eu.siacs.conversations.ui.XmppActivity.OnValueEdited; import eu.siacs.conversations.ui.adapter.MessageAdapter; import eu.siacs.conversations.ui.adapter.MessageAdapter.OnContactPictureClicked; import eu.siacs.conversations.ui.adapter.MessageAdapter.OnContactPictureLongClicked; @@ -26,10 +27,8 @@ import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.IntentSender; -import android.content.SharedPreferences; import android.content.IntentSender.SendIntentException; import android.os.Bundle; -import android.preference.PreferenceManager; import android.text.Editable; import android.text.Selection; import android.view.Gravity; @@ -67,7 +66,6 @@ public class ConversationFragment extends Fragment { private TextView snackbarMessage; private TextView snackbarAction; - private boolean useSubject = true; private boolean messagesLoaded = false; private IntentSender askForPassphraseIntent = null; @@ -131,6 +129,26 @@ public class ConversationFragment extends Fragment { } }; + private OnClickListener enterPassword = new OnClickListener() { + + @Override + public void onClick(View v) { + MucOptions muc = conversation.getMucOptions(); + String password = muc.getPassword(); + if (password == null) { + password = ""; + } + activity.quickPasswordEdit(password, new OnValueEdited() { + + @Override + public void onValueEdited(String value) { + activity.xmppConnectionService.providePasswordForMuc( + conversation, value); + } + }); + } + }; + private OnScrollListener mOnScrollListener = new OnScrollListener() { @Override @@ -160,6 +178,9 @@ public class ConversationFragment extends Fragment { private ConversationActivity activity; private void sendMessage() { + if (this.conversation == null) { + return; + } if (mEditMessage.getText().length() < 1) { if (this.conversation.getMode() == Conversation.MODE_MULTI) { conversation.setNextPresence(null); @@ -168,7 +189,8 @@ public class ConversationFragment extends Fragment { return; } Message message = new Message(conversation, mEditMessage.getText() - .toString(), conversation.getNextEncryption()); + .toString(), conversation.getNextEncryption(activity + .forceEncryption())); if (conversation.getMode() == Conversation.MODE_MULTI) { if (conversation.getNextPresence() != null) { message.setPresence(conversation.getNextPresence()); @@ -176,9 +198,9 @@ public class ConversationFragment extends Fragment { conversation.setNextPresence(null); } } - if (conversation.getNextEncryption() == Message.ENCRYPTION_OTR) { + if (conversation.getNextEncryption(activity.forceEncryption()) == Message.ENCRYPTION_OTR) { sendOtrMessage(message); - } else if (conversation.getNextEncryption() == Message.ENCRYPTION_PGP) { + } else if (conversation.getNextEncryption(activity.forceEncryption()) == Message.ENCRYPTION_PGP) { sendPgpMessage(message); } else { sendPlainTextMessage(message); @@ -192,7 +214,7 @@ public class ConversationFragment extends Fragment { R.string.send_private_message_to, conversation.getNextPresence())); } else { - switch (conversation.getNextEncryption()) { + switch (conversation.getNextEncryption(activity.forceEncryption())) { case Message.ENCRYPTION_NONE: mEditMessage .setHint(getString(R.string.send_plain_text_message)); @@ -287,23 +309,22 @@ public class ConversationFragment extends Fragment { protected void highlightInConference(String nick) { String oldString = mEditMessage.getText().toString().trim(); - if (oldString.isEmpty()) { - mEditMessage.setText(nick + ": "); + if (oldString.isEmpty() || mEditMessage.getSelectionStart() == 0) { + mEditMessage.getText().insert(0, nick + ": "); } else { - mEditMessage.setText(oldString + " " + nick + " "); + if (mEditMessage.getText().charAt( + mEditMessage.getSelectionStart() - 1) != ' ') { + nick = " " + nick; + } + mEditMessage.getText().insert(mEditMessage.getSelectionStart(), + nick + " "); } - int position = mEditMessage.length(); - Editable etext = mEditMessage.getText(); - Selection.setSelection(etext, position); } @Override public void onStart() { super.onStart(); this.activity = (ConversationActivity) getActivity(); - SharedPreferences preferences = PreferenceManager - .getDefaultSharedPreferences(activity); - this.useSubject = preferences.getBoolean("use_subject_in_muc", true); if (activity.xmppConnectionServiceBound) { this.onBackendConnected(); } @@ -343,8 +364,7 @@ public class ConversationFragment extends Fragment { activity.getSlidingPaneLayout().closePane(); activity.getActionBar().setDisplayHomeAsUpEnabled(true); activity.getActionBar().setHomeButtonEnabled(true); - activity.getActionBar().setTitle( - conversation.getName(useSubject)); + activity.getActionBar().setTitle(conversation.getName()); activity.invalidateOptionsMenu(); } } @@ -390,7 +410,17 @@ public class ConversationFragment extends Fragment { final ConversationActivity activity = (ConversationActivity) getActivity(); if (this.conversation != null) { final Contact contact = this.conversation.getContact(); - if (!contact.showInRoster() + if (this.conversation.isMuted()) { + showSnackbar(R.string.notifications_disabled, R.string.enable, + new OnClickListener() { + + @Override + public void onClick(View v) { + conversation.setMutedTill(0); + updateMessages(); + } + }); + } else if (!contact.showInRoster() && contact .getOption(Contact.Options.PENDING_SUBSCRIPTION_REQUEST)) { showSnackbar(R.string.contact_added_you, R.string.add_back, @@ -412,15 +442,11 @@ public class ConversationFragment extends Fragment { break; } } + this.messageList.clear(); if (this.conversation.getMessages().size() == 0) { - this.messageList.clear(); messagesLoaded = false; } else { - for (Message message : this.conversation.getMessages()) { - if (!this.messageList.contains(message)) { - this.messageList.add(message); - } - } + this.messageList.addAll(this.conversation.getMessages()); messagesLoaded = true; updateStatusMessages(); } @@ -432,12 +458,22 @@ public class ConversationFragment extends Fragment { } else { if (!conversation.getMucOptions().online() && conversation.getAccount().getStatus() == Account.STATUS_ONLINE) { - if (conversation.getMucOptions().getError() == MucOptions.ERROR_NICK_IN_USE) { + int error = conversation.getMucOptions().getError(); + switch (error) { + case MucOptions.ERROR_NICK_IN_USE: showSnackbar(R.string.nick_in_use, R.string.edit, clickToMuc); - } else if (conversation.getMucOptions().getError() == MucOptions.ERROR_ROOM_NOT_FOUND) { + break; + case MucOptions.ERROR_ROOM_NOT_FOUND: showSnackbar(R.string.conference_not_found, R.string.leave, leaveMuc); + break; + case MucOptions.ERROR_PASSWORD_REQUIRED: + showSnackbar(R.string.conference_requires_password, + R.string.enter_password, enterPassword); + break; + default: + break; } } } @@ -445,7 +481,6 @@ public class ConversationFragment extends Fragment { updateChatMsgHint(); if (!activity.shouldPaneBeOpen()) { activity.xmppConnectionService.markRead(conversation); - // TODO update notifications UIHelper.updateNotification(getActivity(), activity.getConversationList(), null, false); activity.updateConversationList(); @@ -463,23 +498,15 @@ public class ConversationFragment extends Fragment { } protected void updateStatusMessages() { - boolean addedStatusMsg = false; if (conversation.getMode() == Conversation.MODE_SINGLE) { for (int i = this.messageList.size() - 1; i >= 0; --i) { - if (addedStatusMsg) { - if (this.messageList.get(i).getType() == Message.TYPE_STATUS) { - this.messageList.remove(i); - --i; - } + if (this.messageList.get(i).getStatus() == Message.STATUS_RECEIVED) { + return; } else { - if (this.messageList.get(i).getStatus() == Message.STATUS_RECEIVED) { - addedStatusMsg = true; - } else { - if (this.messageList.get(i).getStatus() == Message.STATUS_SEND_DISPLAYED) { - this.messageList.add(i + 1, - Message.createStatusMessage(conversation)); - addedStatusMsg = true; - } + if (this.messageList.get(i).getStatus() == Message.STATUS_SEND_DISPLAYED) { + this.messageList.add(i + 1, + Message.createStatusMessage(conversation)); + return; } } } @@ -491,6 +518,7 @@ public class ConversationFragment extends Fragment { .getOtrFingerprints(); if ((latestEncryption == Message.ENCRYPTION_OTR) && (conversation.hasValidOtrSession() + && (!conversation.isMuted()) && (conversation.getOtrSession().getSessionStatus() == SessionStatus.ENCRYPTED) && (!knownFingerprints .contains(conversation.getOtrFingerprint())))) { showSnackbar(R.string.unknown_otr_fingerprint, R.string.verify, diff --git a/src/eu/siacs/conversations/ui/EditAccountActivity.java b/src/eu/siacs/conversations/ui/EditAccountActivity.java index d98a0ca71..bc9461159 100644 --- a/src/eu/siacs/conversations/ui/EditAccountActivity.java +++ b/src/eu/siacs/conversations/ui/EditAccountActivity.java @@ -201,7 +201,8 @@ public class EditAccountActivity extends XmppActivity { this.mSaveButton.setEnabled(true); this.mSaveButton.setTextColor(getPrimaryTextColor()); if (jidToEdit != null) { - if (mAccount!= null && mAccount.getStatus() == Account.STATUS_ONLINE) { + if (mAccount != null + && mAccount.getStatus() == Account.STATUS_ONLINE) { this.mSaveButton.setText(R.string.save); } else { this.mSaveButton.setText(R.string.connect); @@ -324,7 +325,7 @@ public class EditAccountActivity extends XmppActivity { this.mServerInfoPep.setText(R.string.server_info_unavailable); } String fingerprint = this.mAccount - .getOtrFingerprint(getApplicationContext()); + .getOtrFingerprint(xmppConnectionService); if (fingerprint != null) { this.mOtrFingerprintHeadline.setVisibility(View.VISIBLE); this.mOtrFingerprint.setVisibility(View.VISIBLE); diff --git a/src/eu/siacs/conversations/ui/PublishProfilePictureActivity.java b/src/eu/siacs/conversations/ui/PublishProfilePictureActivity.java index c979d1379..f46d92f9a 100644 --- a/src/eu/siacs/conversations/ui/PublishProfilePictureActivity.java +++ b/src/eu/siacs/conversations/ui/PublishProfilePictureActivity.java @@ -46,7 +46,7 @@ public class PublishProfilePictureActivity extends XmppActivity { public void run() { if (mInitialAccountSetup) { startActivity(new Intent(getApplicationContext(), - StartConversationActivity.class)); + StartConversationActivity.class)); } finish(); } @@ -111,7 +111,7 @@ public class PublishProfilePictureActivity extends XmppActivity { public void onClick(View v) { if (mInitialAccountSetup) { startActivity(new Intent(getApplicationContext(), - StartConversationActivity.class)); + StartConversationActivity.class)); } finish(); } diff --git a/src/eu/siacs/conversations/ui/SettingsActivity.java b/src/eu/siacs/conversations/ui/SettingsActivity.java index f8fd94695..6b2807199 100644 --- a/src/eu/siacs/conversations/ui/SettingsActivity.java +++ b/src/eu/siacs/conversations/ui/SettingsActivity.java @@ -1,20 +1,57 @@ package eu.siacs.conversations.ui; +import java.util.Locale; + +import eu.siacs.conversations.R; +import eu.siacs.conversations.entities.Account; +import android.content.SharedPreferences; +import android.content.SharedPreferences.OnSharedPreferenceChangeListener; import android.os.Bundle; +import android.preference.PreferenceManager; -public class SettingsActivity extends XmppActivity { +public class SettingsActivity extends XmppActivity implements + OnSharedPreferenceChangeListener { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - - // Display the fragment as the main content. getFragmentManager().beginTransaction() .replace(android.R.id.content, new SettingsFragment()).commit(); } @Override void onBackendConnected() { - + + } + + @Override + public void onStart() { + super.onStart(); + PreferenceManager.getDefaultSharedPreferences(this) + .registerOnSharedPreferenceChangeListener(this); + } + + @Override + public void onStop() { + super.onStop(); + PreferenceManager.getDefaultSharedPreferences(this) + .unregisterOnSharedPreferenceChangeListener(this); + } + + @Override + public void onSharedPreferenceChanged(SharedPreferences preferences, + String name) { + if (name.equals("resource")) { + String resource = preferences.getString("resource", "mobile") + .toLowerCase(Locale.US); + if (xmppConnectionServiceBound) { + for (Account account : xmppConnectionService.getAccounts()) { + account.setResource(resource); + if (!account.isOptionSet(Account.OPTION_DISABLED)) { + xmppConnectionService.reconnectAccount(account, false); + } + } + } + } } } diff --git a/src/eu/siacs/conversations/ui/ShareWithActivity.java b/src/eu/siacs/conversations/ui/ShareWithActivity.java index 57b4ba31c..9fbc3db10 100644 --- a/src/eu/siacs/conversations/ui/ShareWithActivity.java +++ b/src/eu/siacs/conversations/ui/ShareWithActivity.java @@ -1,37 +1,41 @@ package eu.siacs.conversations.ui; import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashSet; import java.util.List; -import java.util.Set; +import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.entities.Account; -import eu.siacs.conversations.entities.Contact; import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.entities.Message; -import eu.siacs.conversations.utils.UIHelper; +import eu.siacs.conversations.ui.adapter.ConversationAdapter; import android.app.PendingIntent; import android.content.Intent; -import android.content.SharedPreferences; -import android.graphics.Bitmap; import android.net.Uri; import android.os.Bundle; -import android.preference.PreferenceManager; +import android.util.Log; +import android.view.Menu; +import android.view.MenuItem; import android.view.View; -import android.view.View.OnClickListener; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.TextView; +import android.widget.AdapterView; +import android.widget.AdapterView.OnItemClickListener; +import android.widget.ListView; import android.widget.Toast; public class ShareWithActivity extends XmppActivity { - private LinearLayout conversations; - private LinearLayout contacts; - private boolean isImage = false; + private class Share { + public Uri uri; + public String account; + public String contact; + public String text; + } + + private Share share; + + private static final int REQUEST_START_NEW_CONVERSATION = 0x0501; + private ListView mListView; + private List<Conversation> mConversations = new ArrayList<Conversation>(); private UiCallback<Message> attachImageCallback = new UiCallback<Message>() { @@ -53,110 +57,110 @@ public class ShareWithActivity extends XmppActivity { } }; + protected void onActivityResult(int requestCode, int resultCode, + final Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (requestCode == REQUEST_START_NEW_CONVERSATION + && resultCode == RESULT_OK) { + share.contact = data.getStringExtra("contact"); + share.account = data.getStringExtra("account"); + Log.d(Config.LOGTAG, "contact: " + share.contact + " account:" + + share.account); + } + if (xmppConnectionServiceBound && share != null + && share.contact != null && share.account != null) { + share(); + } + } + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + getActionBar().setDisplayHomeAsUpEnabled(false); + getActionBar().setHomeButtonEnabled(false); + setContentView(R.layout.share_with); setTitle(getString(R.string.title_activity_sharewith)); - contacts = (LinearLayout) findViewById(R.id.contacts); - conversations = (LinearLayout) findViewById(R.id.conversations); + mListView = (ListView) findViewById(R.id.choose_conversation_list); + ConversationAdapter mAdapter = new ConversationAdapter(this, + this.mConversations); + mListView.setAdapter(mAdapter); + mListView.setOnItemClickListener(new OnItemClickListener() { + + @Override + public void onItemClick(AdapterView<?> arg0, View arg1, + int position, long arg3) { + Conversation conversation = mConversations.get(position); + if (conversation.getMode() == Conversation.MODE_SINGLE + || share.uri == null) { + share(mConversations.get(position)); + } + } + }); + this.share = new Share(); } - public View createContactView(String name, String msgTxt, Bitmap bm) { - View view = (View) getLayoutInflater().inflate(R.layout.contact, null); - view.setBackgroundResource(R.drawable.greybackground); - TextView contactName = (TextView) view - .findViewById(R.id.contact_display_name); - contactName.setText(name); - TextView msg = (TextView) view.findViewById(R.id.contact_jid); - msg.setText(msgTxt); - ImageView imageView = (ImageView) view.findViewById(R.id.contact_photo); - imageView.setImageBitmap(bm); - return view; + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.share_with, menu); + return true; } @Override - void onBackendConnected() { - this.isImage = (getIntent().getType() != null && getIntent().getType() - .startsWith("image/")); - SharedPreferences preferences = PreferenceManager - .getDefaultSharedPreferences(this); - boolean useSubject = preferences.getBoolean("use_subject_in_muc", true); - - Set<Contact> displayedContacts = new HashSet<Contact>(); - conversations.removeAllViews(); - List<Conversation> convList = new ArrayList<Conversation>(); - xmppConnectionService.populateWithOrderedConversations(convList); - Collections.sort(convList, new Comparator<Conversation>() { - @Override - public int compare(Conversation lhs, Conversation rhs) { - return (int) (rhs.getLatestMessage().getTimeSent() - lhs - .getLatestMessage().getTimeSent()); - } - }); - for (final Conversation conversation : convList) { - if (!isImage || conversation.getMode() == Conversation.MODE_SINGLE) { - View view = createContactView(conversation.getName(useSubject), - conversation.getLatestMessage().getBody().trim(), - conversation.getImage(getApplicationContext(), 48)); - view.setOnClickListener(new OnClickListener() { - - @Override - public void onClick(View v) { - share(conversation); - } - }); - conversations.addView(view); - displayedContacts.add(conversation.getContact()); - } - } - contacts.removeAllViews(); - List<Contact> contactsList = new ArrayList<Contact>(); - for (Account account : xmppConnectionService.getAccounts()) { - for (Contact contact : account.getRoster().getContacts()) { - if (!displayedContacts.contains(contact) - && (contact.showInRoster())) { - contactsList.add(contact); - } - } + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.action_add: + Intent intent = new Intent(getApplicationContext(), + ChooseContactActivity.class); + startActivityForResult(intent, REQUEST_START_NEW_CONVERSATION); + return true; } + return super.onOptionsItemSelected(item); + } - Collections.sort(contactsList, new Comparator<Contact>() { - @Override - public int compare(Contact lhs, Contact rhs) { - return lhs.getDisplayName().compareToIgnoreCase( - rhs.getDisplayName()); - } - }); + @Override + public void onStart() { + if (getIntent().getType() != null + && getIntent().getType().startsWith("image/")) { + this.share.uri = (Uri) getIntent().getParcelableExtra( + Intent.EXTRA_STREAM); + } else { + this.share.text = getIntent().getStringExtra(Intent.EXTRA_TEXT); + } + if (xmppConnectionServiceBound) { + xmppConnectionService.populateWithOrderedConversations( + mConversations, this.share.uri == null); + } + super.onStart(); + } - for (int i = 0; i < contactsList.size(); ++i) { - final Contact contact = contactsList.get(i); - View view = createContactView(contact.getDisplayName(), - contact.getJid(), - contact.getImage(48, getApplicationContext())); - view.setOnClickListener(new OnClickListener() { + @Override + void onBackendConnected() { + if (xmppConnectionServiceBound && share != null + && share.contact != null && share.account != null) { + share(); + return; + } + xmppConnectionService.populateWithOrderedConversations(mConversations, + this.share != null && this.share.uri == null); + } - @Override - public void onClick(View v) { - Conversation conversation = xmppConnectionService - .findOrCreateConversation(contact.getAccount(), - contact.getJid(), false); - share(conversation); - } - }); - contacts.addView(view); + private void share() { + Account account = xmppConnectionService.findAccountByJid(share.account); + if (account == null) { + return; } + Conversation conversation = xmppConnectionService + .findOrCreateConversation(account, share.contact, false); + share(conversation); } private void share(final Conversation conversation) { - String sharedText = null; - if (isImage) { - final Uri uri = (Uri) getIntent().getParcelableExtra( - Intent.EXTRA_STREAM); + if (share.uri != null) { selectPresence(conversation, new OnPresenceSelected() { @Override public void onPresenceSelected() { @@ -164,7 +168,7 @@ public class ShareWithActivity extends XmppActivity { getText(R.string.preparing_image), Toast.LENGTH_LONG).show(); ShareWithActivity.this.xmppConnectionService - .attachImageToConversation(conversation, uri, + .attachImageToConversation(conversation, share.uri, attachImageCallback); switchToConversation(conversation, null, true); finish(); @@ -172,11 +176,10 @@ public class ShareWithActivity extends XmppActivity { }); } else { - sharedText = getIntent().getStringExtra(Intent.EXTRA_TEXT); - switchToConversation(conversation, sharedText, true); + switchToConversation(conversation, this.share.text, true); finish(); } } -} +}
\ No newline at end of file diff --git a/src/eu/siacs/conversations/ui/StartConversationActivity.java b/src/eu/siacs/conversations/ui/StartConversationActivity.java index bd66bd94f..6287070c4 100644 --- a/src/eu/siacs/conversations/ui/StartConversationActivity.java +++ b/src/eu/siacs/conversations/ui/StartConversationActivity.java @@ -191,8 +191,7 @@ public class StartConversationActivity extends XmppActivity { } }); - mConferenceAdapter = new ListItemAdapter(getApplicationContext(), - conferences); + mConferenceAdapter = new ListItemAdapter(this, conferences); mConferenceListFragment.setListAdapter(mConferenceAdapter); mConferenceListFragment.setContextMenu(R.menu.conference_context); mConferenceListFragment @@ -205,8 +204,7 @@ public class StartConversationActivity extends XmppActivity { } }); - mContactsAdapter = new ListItemAdapter(getApplicationContext(), - contacts); + mContactsAdapter = new ListItemAdapter(this, contacts); mContactsListFragment.setListAdapter(mContactsAdapter); mContactsListFragment.setContextMenu(R.menu.contact_context); mContactsListFragment @@ -340,7 +338,7 @@ public class StartConversationActivity extends XmppActivity { String contactJid = jid.getText().toString(); Account account = xmppConnectionService .findAccountByJid(accountJid); - if (account==null) { + if (account == null) { dialog.dismiss(); return; } diff --git a/src/eu/siacs/conversations/ui/UiCallback.java b/src/eu/siacs/conversations/ui/UiCallback.java index 05a869f7d..c80199e17 100644 --- a/src/eu/siacs/conversations/ui/UiCallback.java +++ b/src/eu/siacs/conversations/ui/UiCallback.java @@ -4,6 +4,8 @@ import android.app.PendingIntent; public interface UiCallback<T> { public void success(T object); + public void error(int errorCode, T object); + public void userInputRequried(PendingIntent pi, T object); } diff --git a/src/eu/siacs/conversations/ui/XmppActivity.java b/src/eu/siacs/conversations/ui/XmppActivity.java index 44043a794..f13c112a9 100644 --- a/src/eu/siacs/conversations/ui/XmppActivity.java +++ b/src/eu/siacs/conversations/ui/XmppActivity.java @@ -1,5 +1,10 @@ package eu.siacs.conversations.ui; +import java.io.FileNotFoundException; +import java.lang.ref.WeakReference; +import java.util.concurrent.RejectedExecutionException; + +import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Contact; @@ -16,26 +21,34 @@ import android.app.AlertDialog.Builder; import android.content.ComponentName; import android.content.Context; import android.content.DialogInterface; +import android.content.SharedPreferences; import android.content.DialogInterface.OnClickListener; import android.content.IntentSender.SendIntentException; +import android.content.res.Resources; import android.content.Intent; import android.content.ServiceConnection; +import android.graphics.Bitmap; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; import android.net.Uri; +import android.os.AsyncTask; import android.os.Bundle; import android.os.IBinder; +import android.preference.PreferenceManager; +import android.text.InputType; +import android.util.DisplayMetrics; import android.util.Log; import android.view.MenuItem; import android.view.View; import android.view.inputmethod.InputMethodManager; import android.widget.EditText; +import android.widget.ImageView; public abstract class XmppActivity extends Activity { protected static final int REQUEST_ANNOUNCE_PGP = 0x0101; protected static final int REQUEST_INVITE_TO_CONVERSATION = 0x0102; - protected final static String LOGTAG = "xmppService"; - public XmppConnectionService xmppConnectionService; public boolean xmppConnectionServiceBound = false; protected boolean handledViewIntent = false; @@ -45,6 +58,8 @@ public abstract class XmppActivity extends Activity { protected int mWarningTextColor; protected int mPrimaryColor; + private DisplayMetrics metrics; + protected interface OnValueEdited { public void onValueEdited(String value); } @@ -164,11 +179,20 @@ public abstract class XmppActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + metrics = getResources().getDisplayMetrics(); ExceptionHelper.init(getApplicationContext()); mPrimaryTextColor = getResources().getColor(R.color.primarytext); mSecondaryTextColor = getResources().getColor(R.color.secondarytext); mWarningTextColor = getResources().getColor(R.color.warningtext); mPrimaryColor = getResources().getColor(R.color.primary); + if (getPreferences().getBoolean("use_larger_font", false)) { + setTheme(R.style.ConversationsTheme_LargerText); + } + } + + protected SharedPreferences getPreferences() { + return PreferenceManager + .getDefaultSharedPreferences(getApplicationContext()); } public void switchToConversation(Conversation conversation) { @@ -284,16 +308,62 @@ public abstract class XmppActivity extends Activity { builder.create().show(); } - protected void quickEdit(final String previousValue, - final OnValueEdited callback) { + private void showAskForPresenceDialog(final Contact contact) { + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle(contact.getJid()); + builder.setMessage(R.string.request_presence_updates); + builder.setNegativeButton(R.string.cancel, null); + builder.setPositiveButton(R.string.request_now, + new DialogInterface.OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int which) { + if (xmppConnectionServiceBound) { + xmppConnectionService.sendPresencePacket(contact + .getAccount(), xmppConnectionService + .getPresenceGenerator() + .requestPresenceUpdatesFrom(contact)); + } + } + }); + builder.create().show(); + } + + private void warnMutalPresenceSubscription(final Conversation conversation, + final OnPresenceSelected listener) { + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle(conversation.getContact().getJid()); + builder.setMessage(R.string.without_mutual_presence_updates); + builder.setNegativeButton(R.string.cancel, null); + builder.setPositiveButton(R.string.ignore, new OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int which) { + conversation.setNextPresence(null); + if (listener != null) { + listener.onPresenceSelected(); + } + } + }); + builder.create().show(); + } + + protected void quickEdit(String previousValue, OnValueEdited callback) { + quickEdit(previousValue, callback, false); + } + + protected void quickPasswordEdit(String previousValue, + OnValueEdited callback) { + quickEdit(previousValue, callback, true); + } + + private void quickEdit(final String previousValue, + final OnValueEdited callback, boolean password) { AlertDialog.Builder builder = new AlertDialog.Builder(this); View view = (View) getLayoutInflater() .inflate(R.layout.quickedit, null); final EditText editor = (EditText) view.findViewById(R.id.editor); - editor.setText(previousValue); - builder.setView(view); - builder.setNegativeButton(R.string.cancel, null); - builder.setPositiveButton(R.string.edit, new OnClickListener() { + OnClickListener mClickListener = new OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { @@ -302,7 +372,19 @@ public abstract class XmppActivity extends Activity { callback.onValueEdited(value); } } - }); + }; + if (password) { + editor.setInputType(InputType.TYPE_CLASS_TEXT + | InputType.TYPE_TEXT_VARIATION_PASSWORD); + editor.setHint(R.string.password); + builder.setPositiveButton(R.string.accept, mClickListener); + } else { + builder.setPositiveButton(R.string.edit, mClickListener); + } + editor.requestFocus(); + editor.setText(previousValue); + builder.setView(view); + builder.setNegativeButton(R.string.cancel, null); builder.create().show(); } @@ -314,8 +396,17 @@ public abstract class XmppActivity extends Activity { } else { Presences presences = contact.getPresences(); if (presences.size() == 0) { - conversation.setNextPresence(null); - listener.onPresenceSelected(); + if (!contact.getOption(Contact.Options.TO) + && !contact.getOption(Contact.Options.ASKING) + && contact.getAccount().getStatus() == Account.STATUS_ONLINE) { + showAskForPresenceDialog(contact); + } else if (!contact.getOption(Contact.Options.TO) + || !contact.getOption(Contact.Options.FROM)) { + warnMutalPresenceSubscription(conversation, listener); + } else { + conversation.setNextPresence(null); + listener.onPresenceSelected(); + } } else if (presences.size() == 1) { String presence = (String) presences.asStringArray()[0]; conversation.setNextPresence(presence); @@ -370,8 +461,8 @@ public abstract class XmppActivity extends Activity { if (conversation.getMode() == Conversation.MODE_MULTI) { xmppConnectionService.invite(conversation, contactJid); } - Log.d("xmppService", "inviting " + contactJid + " to " - + conversation.getName(true)); + Log.d(Config.LOGTAG, "inviting " + contactJid + " to " + + conversation.getName()); } } @@ -390,4 +481,103 @@ public abstract class XmppActivity extends Activity { public int getPrimaryColor() { return this.mPrimaryColor; } + + class BitmapWorkerTask extends AsyncTask<Message, Void, Bitmap> { + private final WeakReference<ImageView> imageViewReference; + private Message message = null; + + public BitmapWorkerTask(ImageView imageView) { + imageViewReference = new WeakReference<ImageView>(imageView); + } + + @Override + protected Bitmap doInBackground(Message... params) { + message = params[0]; + try { + return xmppConnectionService.getFileBackend().getThumbnail( + message, (int) (metrics.density * 288), false); + } catch (FileNotFoundException e) { + return null; + } + } + + @Override + protected void onPostExecute(Bitmap bitmap) { + if (imageViewReference != null && bitmap != null) { + final ImageView imageView = imageViewReference.get(); + if (imageView != null) { + imageView.setImageBitmap(bitmap); + imageView.setBackgroundColor(0x00000000); + } + } + } + } + + public void loadBitmap(Message message, ImageView imageView) { + Bitmap bm; + try { + bm = xmppConnectionService.getFileBackend().getThumbnail(message, + (int) (metrics.density * 288), true); + } catch (FileNotFoundException e) { + bm = null; + } + if (bm != null) { + imageView.setImageBitmap(bm); + imageView.setBackgroundColor(0x00000000); + } else { + if (cancelPotentialWork(message, imageView)) { + imageView.setBackgroundColor(0xff333333); + final BitmapWorkerTask task = new BitmapWorkerTask(imageView); + final AsyncDrawable asyncDrawable = new AsyncDrawable( + getResources(), null, task); + imageView.setImageDrawable(asyncDrawable); + try { + task.execute(message); + } catch (RejectedExecutionException e) { + return; + } + } + } + } + + public static boolean cancelPotentialWork(Message message, + ImageView imageView) { + final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView); + + if (bitmapWorkerTask != null) { + final Message oldMessage = bitmapWorkerTask.message; + if (oldMessage == null || message != oldMessage) { + bitmapWorkerTask.cancel(true); + } else { + return false; + } + } + return true; + } + + private static BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) { + if (imageView != null) { + final Drawable drawable = imageView.getDrawable(); + if (drawable instanceof AsyncDrawable) { + final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable; + return asyncDrawable.getBitmapWorkerTask(); + } + } + return null; + } + + static class AsyncDrawable extends BitmapDrawable { + private final WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference; + + public AsyncDrawable(Resources res, Bitmap bitmap, + BitmapWorkerTask bitmapWorkerTask) { + super(res, bitmap); + bitmapWorkerTaskReference = new WeakReference<BitmapWorkerTask>( + bitmapWorkerTask); + } + + public BitmapWorkerTask getBitmapWorkerTask() { + return bitmapWorkerTaskReference.get(); + } + } } diff --git a/src/eu/siacs/conversations/ui/adapter/AccountAdapter.java b/src/eu/siacs/conversations/ui/adapter/AccountAdapter.java index cd8b376fc..5c25bf346 100644 --- a/src/eu/siacs/conversations/ui/adapter/AccountAdapter.java +++ b/src/eu/siacs/conversations/ui/adapter/AccountAdapter.java @@ -14,9 +14,9 @@ import android.widget.ImageView; import android.widget.TextView; public class AccountAdapter extends ArrayAdapter<Account> { - + private XmppActivity activity; - + public AccountAdapter(XmppActivity activity, List<Account> objects) { super(activity, 0, objects); this.activity = activity; @@ -34,7 +34,7 @@ public class AccountAdapter extends ArrayAdapter<Account> { jid.setText(account.getJid()); TextView statusView = (TextView) view.findViewById(R.id.account_status); ImageView imageView = (ImageView) view.findViewById(R.id.account_image); - imageView.setImageBitmap(account.getImage(activity,48)); + imageView.setImageBitmap(account.getImage(activity, 48)); switch (account.getStatus()) { case Account.STATUS_DISABLED: statusView.setText(getContext().getString( diff --git a/src/eu/siacs/conversations/ui/adapter/ConversationAdapter.java b/src/eu/siacs/conversations/ui/adapter/ConversationAdapter.java index fcc576018..bfcba135e 100644 --- a/src/eu/siacs/conversations/ui/adapter/ConversationAdapter.java +++ b/src/eu/siacs/conversations/ui/adapter/ConversationAdapter.java @@ -2,10 +2,12 @@ package eu.siacs.conversations.ui.adapter; import java.util.List; +import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.ui.ConversationActivity; +import eu.siacs.conversations.ui.XmppActivity; import eu.siacs.conversations.utils.UIHelper; import android.content.Context; import android.graphics.Color; @@ -19,9 +21,9 @@ import android.widget.TextView; public class ConversationAdapter extends ArrayAdapter<Conversation> { - ConversationActivity activity; + private XmppActivity activity; - public ConversationAdapter(ConversationActivity activity, + public ConversationAdapter(XmppActivity activity, List<Conversation> conversations) { super(activity, 0, conversations); this.activity = activity; @@ -36,18 +38,21 @@ public class ConversationAdapter extends ArrayAdapter<Conversation> { parent, false); } Conversation conv = getItem(position); - if (!activity.getSlidingPaneLayout().isSlideable()) { - if (conv == activity.getSelectedConversation()) { - view.setBackgroundColor(0xffdddddd); + if (this.activity instanceof ConversationActivity) { + ConversationActivity activity = (ConversationActivity) this.activity; + if (!activity.getSlidingPaneLayout().isSlideable()) { + if (conv == activity.getSelectedConversation()) { + view.setBackgroundColor(0xffdddddd); + } else { + view.setBackgroundColor(Color.TRANSPARENT); + } } else { view.setBackgroundColor(Color.TRANSPARENT); } - } else { - view.setBackgroundColor(Color.TRANSPARENT); } TextView convName = (TextView) view .findViewById(R.id.conversation_name); - convName.setText(conv.getName(true)); + convName.setText(conv.getName()); TextView convLastMsg = (TextView) view .findViewById(R.id.conversation_lastmsg); ImageView imagePreview = (ImageView) view @@ -59,10 +64,12 @@ public class ConversationAdapter extends ArrayAdapter<Conversation> { || latestMessage.getType() == Message.TYPE_PRIVATE) { if ((latestMessage.getEncryption() != Message.ENCRYPTION_PGP) && (latestMessage.getEncryption() != Message.ENCRYPTION_DECRYPTION_FAILED)) { - convLastMsg.setText(conv.getLatestMessage().getBody()); + String body = Config.PARSE_EMOTICONS ? UIHelper + .transformAsciiEmoticons(latestMessage.getBody()) + : latestMessage.getBody(); + convLastMsg.setText(body); } else { - convLastMsg.setText(activity - .getText(R.string.encrypted_message_received)); + convLastMsg.setText(R.string.encrypted_message_received); } convLastMsg.setVisibility(View.VISIBLE); imagePreview.setVisibility(View.GONE); @@ -75,11 +82,9 @@ public class ConversationAdapter extends ArrayAdapter<Conversation> { convLastMsg.setVisibility(View.VISIBLE); imagePreview.setVisibility(View.GONE); if (latestMessage.getStatus() == Message.STATUS_RECEIVED_OFFER) { - convLastMsg.setText(activity - .getText(R.string.image_offered_for_download)); + convLastMsg.setText(R.string.image_offered_for_download); } else if (latestMessage.getStatus() == Message.STATUS_RECEIVING) { - convLastMsg.setText(activity - .getText(R.string.receiving_image)); + convLastMsg.setText(R.string.receiving_image); } else { convLastMsg.setText(""); } diff --git a/src/eu/siacs/conversations/ui/adapter/KnownHostsAdapter.java b/src/eu/siacs/conversations/ui/adapter/KnownHostsAdapter.java index d286052cb..0534bc25c 100644 --- a/src/eu/siacs/conversations/ui/adapter/KnownHostsAdapter.java +++ b/src/eu/siacs/conversations/ui/adapter/KnownHostsAdapter.java @@ -19,7 +19,8 @@ public class KnownHostsAdapter extends ArrayAdapter<String> { final String[] split = constraint.toString().split("@"); if (split.length == 1) { for (String domain : domains) { - suggestions.add(split[0].toLowerCase(Locale.getDefault()) + "@" + domain); + suggestions.add(split[0].toLowerCase(Locale + .getDefault()) + "@" + domain); } } else if (split.length == 2) { for (String domain : domains) { @@ -27,7 +28,8 @@ public class KnownHostsAdapter extends ArrayAdapter<String> { suggestions.clear(); break; } else if (domain.contains(split[1])) { - suggestions.add(split[0].toLowerCase(Locale.getDefault()) + "@" + domain); + suggestions.add(split[0].toLowerCase(Locale + .getDefault()) + "@" + domain); } } } else { diff --git a/src/eu/siacs/conversations/ui/adapter/MessageAdapter.java b/src/eu/siacs/conversations/ui/adapter/MessageAdapter.java index 2452a5555..967042d80 100644 --- a/src/eu/siacs/conversations/ui/adapter/MessageAdapter.java +++ b/src/eu/siacs/conversations/ui/adapter/MessageAdapter.java @@ -3,9 +3,11 @@ package eu.siacs.conversations.ui.adapter; import java.util.HashMap; import java.util.List; +import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.entities.Contact; import eu.siacs.conversations.entities.Conversation; +import eu.siacs.conversations.entities.Downloadable; import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.ui.ConversationActivity; import eu.siacs.conversations.utils.UIHelper; @@ -14,7 +16,6 @@ import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.Typeface; -import android.text.Html; import android.text.Spannable; import android.text.SpannableString; import android.text.style.ForegroundColorSpan; @@ -34,8 +35,9 @@ import android.widget.Toast; public class MessageAdapter extends ArrayAdapter<Message> { private static final int SENT = 0; - private static final int RECIEVED = 1; + private static final int RECEIVED = 1; private static final int STATUS = 2; + private static final int NULL = 3; private ConversationActivity activity; @@ -67,22 +69,25 @@ public class MessageAdapter extends ArrayAdapter<Message> { public void setOnContactPictureClicked(OnContactPictureClicked listener) { this.mOnContactPictureClickedListener = listener; } - - public void setOnContactPictureLongClicked(OnContactPictureLongClicked listener) { + + public void setOnContactPictureLongClicked( + OnContactPictureLongClicked listener) { this.mOnContactPictureLongClickedListener = listener; } @Override public int getViewTypeCount() { - return 3; + return 4; } @Override public int getItemViewType(int position) { - if (getItem(position).getType() == Message.TYPE_STATUS) { + if (getItem(position).wasMergedIntoPrevious()) { + return NULL; + } else if (getItem(position).getType() == Message.TYPE_STATUS) { return STATUS; } else if (getItem(position).getStatus() <= Message.STATUS_RECEIVED) { - return RECIEVED; + return RECEIVED; } else { return SENT; } @@ -93,7 +98,7 @@ public class MessageAdapter extends ArrayAdapter<Message> { String info = null; boolean error = false; boolean multiReceived = message.getConversation().getMode() == Conversation.MODE_MULTI - && message.getStatus() <= Message.STATUS_RECEIVED; + && message.getMergedStatus() <= Message.STATUS_RECEIVED; if (message.getType() == Message.TYPE_IMAGE) { String[] fileParams = message.getBody().split(","); try { @@ -103,7 +108,7 @@ public class MessageAdapter extends ArrayAdapter<Message> { filesize = "0 KB"; } } - switch (message.getStatus()) { + switch (message.getMergedStatus()) { case Message.STATUS_WAITING: info = getContext().getString(R.string.waiting); break; @@ -151,7 +156,7 @@ public class MessageAdapter extends ArrayAdapter<Message> { } String formatedTime = UIHelper.readableTimeDifference(getContext(), - message.getTimeSent()); + message.getMergedTimeSent()); if (message.getStatus() <= Message.STATUS_RECEIVED) { if ((filesize != null) && (info != null)) { viewHolder.time.setText(filesize + " \u00B7 " + info); @@ -212,11 +217,15 @@ public class MessageAdapter extends ArrayAdapter<Message> { viewHolder.messageBody.setVisibility(View.VISIBLE); if (message.getBody() != null) { if (message.getType() != Message.TYPE_PRIVATE) { - viewHolder.messageBody.setText(message.getBody().trim()); + String body = Config.PARSE_EMOTICONS ? UIHelper + .transformAsciiEmoticons(message.getMergedBody()) + : message.getMergedBody(); + viewHolder.messageBody.setText(body); } else { String privateMarker; if (message.getStatus() <= Message.STATUS_RECEIVED) { - privateMarker = activity.getString(R.string.private_message); + privateMarker = activity + .getString(R.string.private_message); } else { String to; if (message.getPresence() != null) { @@ -224,11 +233,18 @@ public class MessageAdapter extends ArrayAdapter<Message> { } else { to = message.getCounterpart(); } - privateMarker = activity.getString(R.string.private_message_to, to); + privateMarker = activity.getString( + R.string.private_message_to, to); } - SpannableString span = new SpannableString(privateMarker+" "+message.getBody()); - span.setSpan(new ForegroundColorSpan(activity.getSecondaryTextColor()), 0, privateMarker.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); - span.setSpan(new StyleSpan(android.graphics.Typeface.BOLD), 0, privateMarker.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + SpannableString span = new SpannableString(privateMarker + " " + + message.getBody()); + span.setSpan( + new ForegroundColorSpan(activity + .getSecondaryTextColor()), 0, privateMarker + .length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + span.setSpan(new StyleSpan(android.graphics.Typeface.BOLD), 0, + privateMarker.length(), + Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); viewHolder.messageBody.setText(span); } } else { @@ -301,6 +317,10 @@ public class MessageAdapter extends ArrayAdapter<Message> { if (view == null) { viewHolder = new ViewHolder(); switch (type) { + case NULL: + view = (View) activity.getLayoutInflater().inflate( + R.layout.message_null, parent, false); + break; case SENT: view = (View) activity.getLayoutInflater().inflate( R.layout.message_sent, parent, false); @@ -319,7 +339,7 @@ public class MessageAdapter extends ArrayAdapter<Message> { .findViewById(R.id.message_time); view.setTag(viewHolder); break; - case RECIEVED: + case RECEIVED: view = (View) activity.getLayoutInflater().inflate( R.layout.message_received, parent, false); viewHolder.message_box = (LinearLayout) view @@ -362,7 +382,7 @@ public class MessageAdapter extends ArrayAdapter<Message> { @Override public void onClick(View v) { String name = item.getConversation() - .getName(true); + .getName(); String read = getContext() .getString( R.string.contact_has_read_up_to_this_point, @@ -382,11 +402,11 @@ public class MessageAdapter extends ArrayAdapter<Message> { viewHolder = (ViewHolder) view.getTag(); } - if (type == STATUS) { + if (type == STATUS || type == NULL) { return view; } - if (type == RECIEVED) { + if (type == RECEIVED) { if (item.getConversation().getMode() == Conversation.MODE_MULTI) { Contact contact = item.getContact(); if (contact != null) { @@ -394,10 +414,11 @@ public class MessageAdapter extends ArrayAdapter<Message> { contact, getContext())); } else { String name = item.getPresence(); - if (name==null) { + if (name == null) { name = item.getCounterpart(); } - viewHolder.contact_picture.setImageBitmap(mBitmapCache.get(name, getContext())); + viewHolder.contact_picture.setImageBitmap(mBitmapCache.get( + name, getContext())); } viewHolder.contact_picture .setOnClickListener(new OnClickListener() { @@ -412,18 +433,20 @@ public class MessageAdapter extends ArrayAdapter<Message> { } }); - viewHolder.contact_picture.setOnLongClickListener(new OnLongClickListener() { - - @Override - public boolean onLongClick(View v) { - if (MessageAdapter.this.mOnContactPictureLongClickedListener != null) { - MessageAdapter.this.mOnContactPictureLongClickedListener.onContactPictureLongClicked(item); - return true; - } else { - return false; - } - } - }); + viewHolder.contact_picture + .setOnLongClickListener(new OnLongClickListener() { + + @Override + public boolean onLongClick(View v) { + if (MessageAdapter.this.mOnContactPictureLongClickedListener != null) { + MessageAdapter.this.mOnContactPictureLongClickedListener + .onContactPictureLongClicked(item); + return true; + } else { + return false; + } + } + }); } } @@ -439,10 +462,10 @@ public class MessageAdapter extends ArrayAdapter<Message> { @Override public void onClick(View v) { - JingleConnection connection = item - .getJingleConnection(); - if (connection != null) { - connection.accept(); + Downloadable downloadable = item + .getDownloadable(); + if (downloadable != null) { + downloadable.start(); } } }); @@ -522,7 +545,7 @@ public class MessageAdapter extends ArrayAdapter<Message> { public interface OnContactPictureClicked { public void onContactPictureClicked(Message message); } - + public interface OnContactPictureLongClicked { public void onContactPictureLongClicked(Message message); } |