diff options
Diffstat (limited to 'src/main/java/eu/siacs')
22 files changed, 2028 insertions, 1457 deletions
diff --git a/src/main/java/eu/siacs/conversations/Config.java b/src/main/java/eu/siacs/conversations/Config.java index 14605cf09..9361fb0d6 100644 --- a/src/main/java/eu/siacs/conversations/Config.java +++ b/src/main/java/eu/siacs/conversations/Config.java @@ -9,11 +9,12 @@ public final class Config { public static final String LOGTAG = "conversations"; - public static final String DOMAIN_LOCK = null; //only allow account creation for this domain + public static final String DOMAIN_LOCK = "pix-art.de"; //only allow account creation for this domain public static final boolean DISALLOW_REGISTRATION_IN_UI = false; //hide the register checkbox - public static final boolean HIDE_PGP_IN_UI = false; //some more consumer focused clients might want to disable OpenPGP + public static final boolean HIDE_PGP_IN_UI = true; //some more consumer focused clients might want to disable OpenPGP + public static final boolean HIDE_ENCRYPTION_IN_UI = false; //completely hide encryption options in menu bar - public static final boolean LEGACY_NAMESPACE_HTTP_UPLOAD = false; + public static final boolean LEGACY_NAMESPACE_HTTP_UPLOAD = false; // true = 'eu:siacs:conversations:http:upload' false = 'urn:xmpp:http:upload' public static final int PING_MAX_INTERVAL = 300; public static final int PING_MIN_INTERVAL = 30; @@ -23,7 +24,7 @@ public final class Config { public static final int CARBON_GRACE_PERIOD = 90; public static final int MINI_GRACE_PERIOD = 750; - public static final int AVATAR_SIZE = 192; + public static final int AVATAR_SIZE = 640; public static final Bitmap.CompressFormat AVATAR_FORMAT = Bitmap.CompressFormat.WEBP; public static final int IMAGE_SIZE = 1920; @@ -57,7 +58,10 @@ public final class Config { public static final int MAM_MAX_MESSAGES = 500; public static final ChatState DEFAULT_CHATSTATE = ChatState.ACTIVE; - public static final int TYPING_TIMEOUT = 8; + public static final int TYPING_TIMEOUT = 5; + + public static final String UPDATE_URL = "http://xmpp.pix-art.de/Conversations/update/"; + public static final long UPDATE_CHECK_TIMER = 24 * 60 * 60; // in seconds public static final String ENABLED_CIPHERS[] = { "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", diff --git a/src/main/java/eu/siacs/conversations/entities/Contact.java b/src/main/java/eu/siacs/conversations/entities/Contact.java index f924c05a1..f5fa88d7a 100644 --- a/src/main/java/eu/siacs/conversations/entities/Contact.java +++ b/src/main/java/eu/siacs/conversations/entities/Contact.java @@ -149,6 +149,9 @@ public class Contact implements ListItem, Blockable { if (isBlocked()) { tags.add(new Tag("blocked", 0xff2e2f3b)); } + if (!getMostAvailableResource().equals("")){ + tags.add(new Tag(getMostAvailableResource(), 0xff37b8a9)); + } return tags; } @@ -239,6 +242,10 @@ public class Contact implements ListItem, Blockable { return this.presences.getMostAvailableStatus(); } + public String getMostAvailableResource() { + return this.presences.getMostAvailableResource(); + } + public boolean setPhotoUri(String uri) { if (uri != null && !uri.equals(this.photoUri)) { this.photoUri = uri; diff --git a/src/main/java/eu/siacs/conversations/entities/Conversation.java b/src/main/java/eu/siacs/conversations/entities/Conversation.java index 473ef0fe0..ee1eb2110 100644 --- a/src/main/java/eu/siacs/conversations/entities/Conversation.java +++ b/src/main/java/eu/siacs/conversations/entities/Conversation.java @@ -20,6 +20,7 @@ import java.util.Iterator; import java.util.List; import eu.siacs.conversations.Config; +import eu.siacs.conversations.R; import eu.siacs.conversations.xmpp.chatstate.ChatState; import eu.siacs.conversations.xmpp.jid.InvalidJidException; import eu.siacs.conversations.xmpp.jid.Jid; @@ -367,6 +368,19 @@ public class Conversation extends AbstractEntity implements Blockable { return this.getContact().getDisplayName(); } } + + public String getParticipants() { + if (getMode() == MODE_MULTI) { + String generatedName = getMucOptions().createNameFromParticipants(); + if (generatedName != null) { + return generatedName; + } else { + return null; + } + } else { + return null; + } + } public String getAccountUuid() { return this.accountUuid; diff --git a/src/main/java/eu/siacs/conversations/entities/Presences.java b/src/main/java/eu/siacs/conversations/entities/Presences.java index 4729a11b9..a1e90d170 100644 --- a/src/main/java/eu/siacs/conversations/entities/Presences.java +++ b/src/main/java/eu/siacs/conversations/entities/Presences.java @@ -52,6 +52,21 @@ public class Presences { return status; } + public String getMostAvailableResource() { + int status = OFFLINE; + String resource = ""; + synchronized (this.presences) { + Iterator<Entry<String, Integer>> it = presences.entrySet().iterator(); + while (it.hasNext()) { + Entry<String, Integer> entry = it.next(); + if (entry.getValue() < status) + status = entry.getValue(); + resource = entry.getKey(); + } + } + return resource; + } + public static int parseShow(Element show) { if ((show == null) || (show.getContent() == null)) { return Presences.ONLINE; diff --git a/src/main/java/eu/siacs/conversations/entities/Transferable.java b/src/main/java/eu/siacs/conversations/entities/Transferable.java index 016c81bdf..859cda658 100644 --- a/src/main/java/eu/siacs/conversations/entities/Transferable.java +++ b/src/main/java/eu/siacs/conversations/entities/Transferable.java @@ -2,9 +2,58 @@ package eu.siacs.conversations.entities; public interface Transferable { - String[] VALID_IMAGE_EXTENSIONS = {"webp", "jpeg", "jpg", "png", "jpe"}; - String[] VALID_CRYPTO_EXTENSIONS = {"pgp", "gpg", "otr"}; - String[] WELL_KNOWN_EXTENSIONS = {"pdf","m4a","mp4"}; + String[] VALID_IMAGE_EXTENSIONS = { + "webp", + "jpeg", + "jpg", + "png", + "jpe", + "gif", + "tif" + }; + String[] VALID_CRYPTO_EXTENSIONS = { + "pgp", + "gpg", + "otr" + }; + String[] WELL_KNOWN_EXTENSIONS = { + //documents + "pdf", + "doc", + "docx", + "txt", + //audio + "m4a", + "m4b", + "mp3", + "mp2", + "wav", + "aac", + "aif", + "aiff", + "aifc", + "mid", + "midi", + "3gpp", + //video + "avi", + "mp4", + "mpeg", + "mpg", + "mpe", + "mov", + "3gp", + //applications + "apk", + //contact + "vcf", + //calendar + "ics", + //compressed + "zip", + "rar", + + }; int STATUS_UNKNOWN = 0x200; int STATUS_CHECKING = 0x201; diff --git a/src/main/java/eu/siacs/conversations/services/AvatarService.java b/src/main/java/eu/siacs/conversations/services/AvatarService.java index 3cd32d795..00897c9ae 100644 --- a/src/main/java/eu/siacs/conversations/services/AvatarService.java +++ b/src/main/java/eu/siacs/conversations/services/AvatarService.java @@ -45,12 +45,12 @@ public class AvatarService { if (avatar != null || cachedOnly) { return avatar; } - if (contact.getProfilePhoto() != null) { - avatar = mXmppConnectionService.getFileBackend().cropCenterSquare(Uri.parse(contact.getProfilePhoto()), size); - } if (avatar == null && contact.getAvatar() != null) { avatar = mXmppConnectionService.getFileBackend().getAvatar(contact.getAvatar(), size); } + if (avatar == null && contact.getProfilePhoto() != null) { + avatar = mXmppConnectionService.getFileBackend().cropCenterSquare(Uri.parse(contact.getProfilePhoto()), size); + } if (avatar == null) { avatar = get(contact.getDisplayName(), size, cachedOnly); } @@ -283,11 +283,11 @@ public class AvatarService { Contact contact = user.getContact(); if (contact != null) { Uri uri = null; - if (contact.getProfilePhoto() != null) { - uri = Uri.parse(contact.getProfilePhoto()); - } else if (contact.getAvatar() != null) { + if (contact.getAvatar() != null) { uri = mXmppConnectionService.getFileBackend().getAvatarUri( contact.getAvatar()); + } else if (contact.getProfilePhoto() != null) { + uri = Uri.parse(contact.getProfilePhoto()); } if (uri != null) { Bitmap bitmap = mXmppConnectionService.getFileBackend() diff --git a/src/main/java/eu/siacs/conversations/services/CheckAppVersionService.java b/src/main/java/eu/siacs/conversations/services/CheckAppVersionService.java new file mode 100644 index 000000000..33faeaeca --- /dev/null +++ b/src/main/java/eu/siacs/conversations/services/CheckAppVersionService.java @@ -0,0 +1,43 @@ +package eu.siacs.conversations.services; + +import com.google.gson.JsonObject; + +import java.io.IOException; +import java.io.PrintWriter; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +public class CheckAppVersionService extends HttpServlet { + private static final long serialVersionUID = 1L; + + public CheckAppVersionService() { + super(); + } + + protected void doGet(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + doPost(request,response); + } + + protected void doPost(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + + PrintWriter out = response.getWriter(); + response.setContentType("text/html"); + + //send a JSON response with the app Version and file URI + JsonObject myObj = new JsonObject(); + myObj.addProperty("success", false); + myObj.addProperty("latestVersionCode", 2); + myObj.addProperty("latestVersion", "1.0.0"); + myObj.addProperty("changelog", ""); + myObj.addProperty("appURI", ""); + out.println(myObj.toString()); + out.close(); + + } + +} diff --git a/src/main/java/eu/siacs/conversations/services/NotificationService.java b/src/main/java/eu/siacs/conversations/services/NotificationService.java index 125b1c268..3cb962ac6 100644 --- a/src/main/java/eu/siacs/conversations/services/NotificationService.java +++ b/src/main/java/eu/siacs/conversations/services/NotificationService.java @@ -60,12 +60,12 @@ public class NotificationService { public boolean notify(final Message message) { return (message.getStatus() == Message.STATUS_RECEIVED) - && notificationsEnabled() - && !message.getConversation().isMuted() - && (message.getConversation().isPnNA() - || conferenceNotificationsEnabled() - || wasHighlightedOrPrivate(message) - ); + && notificationsEnabled() + && !message.getConversation().isMuted() + && (message.getConversation().isPnNA() + || conferenceNotificationsEnabled() + || wasHighlightedOrPrivate(message) + ); } public void notifyPebble(final Message message) { @@ -179,7 +179,7 @@ public class NotificationService { public void updateNotification(final boolean notify) { final NotificationManager notificationManager = (NotificationManager) mXmppConnectionService - .getSystemService(Context.NOTIFICATION_SERVICE); + .getSystemService(Context.NOTIFICATION_SERVICE); final SharedPreferences preferences = mXmppConnectionService.getPreferences(); final String ringtone = preferences.getString("notification_ringtone", null); @@ -235,7 +235,7 @@ public class NotificationService { conversation = messages.get(0).getConversation(); final String name = conversation.getName(); style.addLine(Html.fromHtml("<b>" + name + "</b> " - + UIHelper.getMessagePreview(mXmppConnectionService,messages.get(0)).first)); + + UIHelper.getMessagePreview(mXmppConnectionService,messages.get(0)).first)); names.append(name); names.append(", "); } @@ -275,9 +275,9 @@ public class NotificationService { Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ? R.drawable.ic_file_download_white_24dp : R.drawable.ic_action_download, mXmppConnectionService.getResources().getString(R.string.download_x_file, - UIHelper.getFileDescriptionString(mXmppConnectionService, message)), + UIHelper.getFileDescriptionString(mXmppConnectionService, message)), createDownloadIntent(message) - ); + ); } if ((message = getFirstLocationMessage(messages)) != null) { mBuilder.addAction(R.drawable.ic_room_white_24dp, @@ -290,16 +290,16 @@ public class NotificationService { } private void modifyForImage(final Builder builder, final Message message, - final ArrayList<Message> messages, final boolean notify) { + final ArrayList<Message> messages, final boolean notify) { try { final Bitmap bitmap = mXmppConnectionService.getFileBackend() - .getThumbnail(message, getPixel(288), false); + .getThumbnail(message, getPixel(200), false); final ArrayList<Message> tmp = new ArrayList<>(); for (final Message msg : messages) { if (msg.getType() == Message.TYPE_TEXT && msg.getTransferable() == null) { tmp.add(msg); - } + } } final BigPictureStyle bigPictureStyle = new NotificationCompat.BigPictureStyle(); bigPictureStyle.bigPicture(bitmap); @@ -318,7 +318,7 @@ public class NotificationService { } private void modifyForTextOnly(final Builder builder, - final ArrayList<Message> messages, final boolean notify) { + final ArrayList<Message> messages, final boolean notify) { builder.setStyle(new NotificationCompat.BigTextStyle().bigText(getMergedBodies(messages))); builder.setContentText(UIHelper.getMessagePreview(mXmppConnectionService,messages.get(0)).first); if (notify) { @@ -333,7 +333,7 @@ public class NotificationService { && message.getEncryption() != Message.ENCRYPTION_PGP && message.getFileParams().height > 0) { return message; - } + } } return null; } @@ -380,7 +380,7 @@ public class NotificationService { private PendingIntent createContentIntent(final String conversationUuid, final String downloadMessageUuid) { final TaskStackBuilder stackBuilder = TaskStackBuilder - .create(mXmppConnectionService); + .create(mXmppConnectionService); stackBuilder.addParentStack(ConversationActivity.class); final Intent viewConversationIntent = new Intent(mXmppConnectionService, @@ -468,7 +468,7 @@ public class NotificationService { private int getPixel(final int dp) { final DisplayMetrics metrics = mXmppConnectionService.getResources() - .getDisplayMetrics(); + .getDisplayMetrics(); return ((int) (dp * metrics.density)); } @@ -478,7 +478,7 @@ public class NotificationService { private boolean inMiniGracePeriod(final Account account) { final int miniGrace = account.getStatus() == Account.State.ONLINE ? Config.MINI_GRACE_PERIOD - : Config.MINI_GRACE_PERIOD * 2; + : Config.MINI_GRACE_PERIOD * 2; return SystemClock.elapsedRealtime() < (this.mLastNotification + miniGrace); } diff --git a/src/main/java/eu/siacs/conversations/services/UpdaterWebService.java b/src/main/java/eu/siacs/conversations/services/UpdaterWebService.java new file mode 100644 index 000000000..3ff6641aa --- /dev/null +++ b/src/main/java/eu/siacs/conversations/services/UpdaterWebService.java @@ -0,0 +1,102 @@ +package eu.siacs.conversations.services; + +import android.app.IntentService; +import android.content.Intent; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.util.Log; + +import org.apache.http.HttpResponse; +import org.apache.http.HttpStatus; +import org.apache.http.StatusLine; +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.conn.params.ConnManagerParams; +import org.apache.http.impl.client.DefaultHttpClient; +import org.apache.http.params.HttpConnectionParams; +import org.apache.http.params.HttpParams; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +import eu.siacs.conversations.Config; +import eu.siacs.conversations.R; +import eu.siacs.conversations.ui.UpdaterActivity.UpdateReceiver; + +public class UpdaterWebService extends IntentService{ + public static final String REQUEST_STRING = ""; + public static final String RESPONSE_MESSAGE = ""; + + private String URL = null; + public static final int REGISTRATION_TIMEOUT = 3 * 1000; + public static final int WAIT_TIMEOUT = 30 * 1000; + + public UpdaterWebService() { + super("UpdaterWebService"); + } + + @Override + protected void onHandleIntent(Intent intent) { + + String requestString = intent.getStringExtra(REQUEST_STRING); + Log.d(Config.LOGTAG, "AppUpdater: " + requestString); + String responseMessage; + PackageInfo pInfo = null; + try { + pInfo = getPackageManager().getPackageInfo(getPackageName(), 0); + } + catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + } + //get the app version Name for display + final String versionName = pInfo.versionName; + + try { + + URL = requestString; + HttpClient httpclient = new DefaultHttpClient(); + HttpParams params = httpclient.getParams(); + + HttpConnectionParams.setConnectionTimeout(params, REGISTRATION_TIMEOUT); + HttpConnectionParams.setSoTimeout(params, WAIT_TIMEOUT); + ConnManagerParams.setTimeout(params, WAIT_TIMEOUT); + + HttpGet httpGet = new HttpGet(URL); + httpGet.setHeader("User-Agent", getString(R.string.app_name) + " " + versionName); + HttpResponse response = httpclient.execute(httpGet); + + StatusLine statusLine = response.getStatusLine(); + Log.d(Config.LOGTAG, "AppUpdater: HTTP Status Code: " + statusLine.getStatusCode()); + if(statusLine.getStatusCode() == HttpStatus.SC_OK){ + ByteArrayOutputStream out = new ByteArrayOutputStream(); + response.getEntity().writeTo(out); + out.close(); + responseMessage = out.toString(); + } else { + Log.e(Config.LOGTAG, "AppUpdater: HTTP1:" + statusLine.getReasonPhrase()); + response.getEntity().getContent().close(); + throw new IOException(statusLine.getReasonPhrase()); + } + + } catch (ClientProtocolException e) { + Log.e(Config.LOGTAG, "AppUpdater: HTTP2:" + e); + responseMessage = ""; + } catch (IOException e) { + Log.e(Config.LOGTAG, "AppUpdater: HTTP3:" + e); + responseMessage = ""; + }catch (Exception e) { + Log.e(Config.LOGTAG, "AppUpdater: HTTP4:" + e); + responseMessage = ""; + } + + + Intent broadcastIntent = new Intent(); + broadcastIntent.setAction(UpdateReceiver.PROCESS_RESPONSE); + broadcastIntent.addCategory(Intent.CATEGORY_DEFAULT); + broadcastIntent.putExtra(RESPONSE_MESSAGE, responseMessage); + sendBroadcast(broadcastIntent); + + } + +}
\ No newline at end of file diff --git a/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java b/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java index 20195256f..82931b4ab 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java @@ -538,11 +538,11 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers Bitmap bm; Contact contact = user.getContact(); if (contact != null) { - bm = avatarService().get(contact, getPixel(48)); + bm = avatarService().get(contact, getPixel(56)); tvDisplayName.setText(contact.getDisplayName()); tvStatus.setText(user.getName() + " \u2022 " + getStatus(user)); } else { - bm = avatarService().get(user.getName(), getPixel(48)); + bm = avatarService().get(user.getName(), getPixel(56)); tvDisplayName.setText(user.getName()); tvStatus.setText(getStatus(user)); diff --git a/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java b/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java index ebac6feba..730b63056 100644 --- a/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java @@ -376,7 +376,7 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd account = contact.getAccount().getJid().toBareJid().toString(); } accountJidTv.setText(getString(R.string.using_account, account)); - badge.setImageBitmap(avatarService().get(contact, getPixel(72))); + badge.setImageBitmap(avatarService().get(contact, getPixel(Config.AVATAR_SIZE))); badge.setOnClickListener(this.onBadgeClick); keys.removeAllViews(); diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java index 1345ada54..b5f8480f3 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java @@ -6,10 +6,12 @@ import android.app.AlertDialog; import android.app.FragmentTransaction; import android.app.PendingIntent; import android.content.ClipData; +import android.content.Context; import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; import android.content.Intent; import android.content.IntentSender.SendIntentException; +import android.content.SharedPreferences; import android.net.Uri; import android.os.Build; import android.os.Bundle; @@ -47,1422 +49,1475 @@ import eu.siacs.conversations.entities.Blockable; import eu.siacs.conversations.entities.Contact; import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.entities.Message; +import eu.siacs.conversations.entities.Presences; import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.services.XmppConnectionService.OnAccountUpdate; import eu.siacs.conversations.services.XmppConnectionService.OnConversationUpdate; import eu.siacs.conversations.services.XmppConnectionService.OnRosterUpdate; import eu.siacs.conversations.ui.adapter.ConversationAdapter; import eu.siacs.conversations.utils.ExceptionHelper; +import eu.siacs.conversations.utils.UIHelper; import eu.siacs.conversations.xmpp.OnUpdateBlocklist; +import eu.siacs.conversations.xmpp.chatstate.ChatState; import eu.siacs.conversations.xmpp.jid.InvalidJidException; import eu.siacs.conversations.xmpp.jid.Jid; public class ConversationActivity extends XmppActivity - implements OnAccountUpdate, OnConversationUpdate, OnRosterUpdate, OnUpdateBlocklist, XmppConnectionService.OnShowErrorToast { - - public static final String ACTION_DOWNLOAD = "eu.siacs.conversations.action.DOWNLOAD"; - - public static final String VIEW_CONVERSATION = "viewConversation"; - public static final String CONVERSATION = "conversationUuid"; - public static final String MESSAGE = "messageUuid"; - public static final String TEXT = "text"; - public static final String NICK = "nick"; - public static final String PRIVATE_MESSAGE = "pm"; - - public static final int REQUEST_SEND_MESSAGE = 0x0201; - public static final int REQUEST_DECRYPT_PGP = 0x0202; - public static final int REQUEST_ENCRYPT_MESSAGE = 0x0207; - public static final int REQUEST_TRUST_KEYS_TEXT = 0x0208; - public static final int REQUEST_TRUST_KEYS_MENU = 0x0209; - public static final int ATTACHMENT_CHOICE_CHOOSE_IMAGE = 0x0301; - public static final int ATTACHMENT_CHOICE_TAKE_PHOTO = 0x0302; - public static final int ATTACHMENT_CHOICE_CHOOSE_FILE = 0x0303; - public static final int ATTACHMENT_CHOICE_RECORD_VOICE = 0x0304; - public static final int ATTACHMENT_CHOICE_LOCATION = 0x0305; - public static final int ATTACHMENT_CHOICE_INVALID = 0x0306; - private static final String STATE_OPEN_CONVERSATION = "state_open_conversation"; - private static final String STATE_PANEL_OPEN = "state_panel_open"; - private static final String STATE_PENDING_URI = "state_pending_uri"; - - private String mOpenConverstaion = null; - private boolean mPanelOpen = true; - final private List<Uri> mPendingImageUris = new ArrayList<>(); - final private List<Uri> mPendingFileUris = new ArrayList<>(); - private Uri mPendingGeoUri = null; - private boolean forbidProcessingPendings = false; - - private boolean conversationWasSelectedByKeyboard = false; - - private View mContentView; - - private List<Conversation> conversationList = new ArrayList<>(); - private Conversation swipedConversation = null; - private Conversation mSelectedConversation = null; - private EnhancedListView listView; - private ConversationFragment mConversationFragment; - - private ArrayAdapter<Conversation> listAdapter; - - private Toast prepareFileToast; - - private boolean mActivityPaused = false; - private AtomicBoolean mRedirected = new AtomicBoolean(false); - - public Conversation getSelectedConversation() { - return this.mSelectedConversation; - } - - public void setSelectedConversation(Conversation conversation) { - this.mSelectedConversation = conversation; - } - - public void showConversationsOverview() { - if (mContentView instanceof SlidingPaneLayout) { - SlidingPaneLayout mSlidingPaneLayout = (SlidingPaneLayout) mContentView; - mSlidingPaneLayout.openPane(); - } - } - - @Override - protected String getShareableUri() { - Conversation conversation = getSelectedConversation(); - if (conversation != null) { - return conversation.getAccount().getShareableUri(); - } else { - return ""; - } - } - - public void hideConversationsOverview() { - if (mContentView instanceof SlidingPaneLayout) { - SlidingPaneLayout mSlidingPaneLayout = (SlidingPaneLayout) mContentView; - mSlidingPaneLayout.closePane(); - } - } - - public boolean isConversationsOverviewHideable() { - if (mContentView instanceof SlidingPaneLayout) { - SlidingPaneLayout mSlidingPaneLayout = (SlidingPaneLayout) mContentView; - return mSlidingPaneLayout.isSlideable(); - } else { - return false; - } - } - - public boolean isConversationsOverviewVisable() { - if (mContentView instanceof SlidingPaneLayout) { - SlidingPaneLayout mSlidingPaneLayout = (SlidingPaneLayout) mContentView; - return mSlidingPaneLayout.isOpen(); - } else { - return true; - } - } - - @Override - protected void onCreate(final Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - if (savedInstanceState != null) { - mOpenConverstaion = savedInstanceState.getString(STATE_OPEN_CONVERSATION, null); - mPanelOpen = savedInstanceState.getBoolean(STATE_PANEL_OPEN, true); - String pending = savedInstanceState.getString(STATE_PENDING_URI, null); - if (pending != null) { - mPendingImageUris.clear(); - mPendingImageUris.add(Uri.parse(pending)); - } - } - - setContentView(R.layout.fragment_conversations_overview); - - this.mConversationFragment = new ConversationFragment(); - FragmentTransaction transaction = getFragmentManager().beginTransaction(); - transaction.replace(R.id.selected_conversation, this.mConversationFragment, "conversation"); - transaction.commit(); - - listView = (EnhancedListView) findViewById(R.id.list); - this.listAdapter = new ConversationAdapter(this, conversationList); - listView.setAdapter(this.listAdapter); - - if (getActionBar() != null) { - getActionBar().setDisplayHomeAsUpEnabled(false); - getActionBar().setHomeButtonEnabled(false); - } - - listView.setOnItemClickListener(new OnItemClickListener() { - - @Override - public void onItemClick(AdapterView<?> arg0, View clickedView, - int position, long arg3) { - if (getSelectedConversation() != conversationList.get(position)) { - setSelectedConversation(conversationList.get(position)); - ConversationActivity.this.mConversationFragment.reInit(getSelectedConversation()); - conversationWasSelectedByKeyboard = false; - } - hideConversationsOverview(); - openConversation(); - } - }); - - listView.setDismissCallback(new EnhancedListView.OnDismissCallback() { - - @Override - public EnhancedListView.Undoable onDismiss(final EnhancedListView enhancedListView, final int position) { - - final int index = listView.getFirstVisiblePosition(); - View v = listView.getChildAt(0); - final int top = (v == null) ? 0 : (v.getTop() - listView.getPaddingTop()); - - try { - swipedConversation = listAdapter.getItem(position); - } catch (IndexOutOfBoundsException e) { - return null; - } - listAdapter.remove(swipedConversation); - xmppConnectionService.markRead(swipedConversation); - - final boolean formerlySelected = (getSelectedConversation() == swipedConversation); - if (position == 0 && listAdapter.getCount() == 0) { - endConversation(swipedConversation, false, true); - return null; - } else if (formerlySelected) { - setSelectedConversation(listAdapter.getItem(0)); - ConversationActivity.this.mConversationFragment - .reInit(getSelectedConversation()); - } - - return new EnhancedListView.Undoable() { - - @Override - public void undo() { - listAdapter.insert(swipedConversation, position); - if (formerlySelected) { - setSelectedConversation(swipedConversation); - ConversationActivity.this.mConversationFragment - .reInit(getSelectedConversation()); - } - swipedConversation = null; - listView.setSelectionFromTop(index + (listView.getChildCount() < position ? 1 : 0), top); - } - - @Override - public void discard() { - if (!swipedConversation.isRead() - && swipedConversation.getMode() == Conversation.MODE_SINGLE) { - swipedConversation = null; - return; - } - endConversation(swipedConversation, false, false); - swipedConversation = null; - } - - @Override - public String getTitle() { - if (swipedConversation.getMode() == Conversation.MODE_MULTI) { - return getResources().getString(R.string.title_undo_swipe_out_muc); - } else { - return getResources().getString(R.string.title_undo_swipe_out_conversation); - } - } - }; - } - }); - listView.enableSwipeToDismiss(); - listView.setSwipingLayout(R.id.swipeable_item); - listView.setUndoStyle(EnhancedListView.UndoStyle.SINGLE_POPUP); - listView.setUndoHideDelay(5000); - listView.setRequireTouchBeforeDismiss(false); - - mContentView = findViewById(R.id.content_view_spl); - if (mContentView == null) { - mContentView = findViewById(R.id.content_view_ll); - } - if (mContentView instanceof SlidingPaneLayout) { - SlidingPaneLayout mSlidingPaneLayout = (SlidingPaneLayout) mContentView; - mSlidingPaneLayout.setParallaxDistance(150); - mSlidingPaneLayout - .setShadowResource(R.drawable.es_slidingpane_shadow); - mSlidingPaneLayout.setSliderFadeColor(0); - mSlidingPaneLayout.setPanelSlideListener(new PanelSlideListener() { - - @Override - public void onPanelOpened(View arg0) { - updateActionBarTitle(); - invalidateOptionsMenu(); - hideKeyboard(); - if (xmppConnectionServiceBound) { - xmppConnectionService.getNotificationService() - .setOpenConversation(null); - } - closeContextMenu(); - } - - @Override - public void onPanelClosed(View arg0) { - listView.discardUndo(); - openConversation(); - } - - @Override - public void onPanelSlide(View arg0, float arg1) { - // TODO Auto-generated method stub - - } - }); - } - } - - @Override - public void switchToConversation(Conversation conversation) { - setSelectedConversation(conversation); - runOnUiThread(new Runnable() { - @Override - public void run() { - ConversationActivity.this.mConversationFragment.reInit(getSelectedConversation()); - openConversation(); - } - }); - } - - private void updateActionBarTitle() { - updateActionBarTitle(isConversationsOverviewHideable() && !isConversationsOverviewVisable()); - } - - private void updateActionBarTitle(boolean titleShouldBeName) { - final ActionBar ab = getActionBar(); - final Conversation conversation = getSelectedConversation(); - if (ab != null) { - if (titleShouldBeName && conversation != null) { - ab.setDisplayHomeAsUpEnabled(true); - ab.setHomeButtonEnabled(true); - if (conversation.getMode() == Conversation.MODE_SINGLE || useSubjectToIdentifyConference()) { - ab.setTitle(conversation.getName()); - } else { - ab.setTitle(conversation.getJid().toBareJid().toString()); - } - } else { - ab.setDisplayHomeAsUpEnabled(false); - ab.setHomeButtonEnabled(false); - ab.setTitle(R.string.app_name); - } - } - } - - private void openConversation() { - this.updateActionBarTitle(); - this.invalidateOptionsMenu(); - if (xmppConnectionServiceBound) { - final Conversation conversation = getSelectedConversation(); - xmppConnectionService.getNotificationService().setOpenConversation(conversation); - sendReadMarkerIfNecessary(conversation); - } - listAdapter.notifyDataSetChanged(); - } - - public void sendReadMarkerIfNecessary(final Conversation conversation) { - if (!mActivityPaused && conversation != null) { - if (!conversation.isRead()) { - xmppConnectionService.sendReadMarker(conversation); - } else { - xmppConnectionService.markRead(conversation); - } - } - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.conversations, menu); - final MenuItem menuSecure = menu.findItem(R.id.action_security); - final MenuItem menuArchive = menu.findItem(R.id.action_archive); - final MenuItem menuMucDetails = menu.findItem(R.id.action_muc_details); - final MenuItem menuContactDetails = menu.findItem(R.id.action_contact_details); - final MenuItem menuAttach = menu.findItem(R.id.action_attach_file); - final MenuItem menuClearHistory = menu.findItem(R.id.action_clear_history); - final MenuItem menuAdd = menu.findItem(R.id.action_add); - final MenuItem menuInviteContact = menu.findItem(R.id.action_invite); - final MenuItem menuMute = menu.findItem(R.id.action_mute); - final MenuItem menuUnmute = menu.findItem(R.id.action_unmute); - - if (isConversationsOverviewVisable() && isConversationsOverviewHideable()) { - menuArchive.setVisible(false); - menuMucDetails.setVisible(false); - menuContactDetails.setVisible(false); - menuSecure.setVisible(false); - menuInviteContact.setVisible(false); - menuAttach.setVisible(false); - menuClearHistory.setVisible(false); - menuMute.setVisible(false); - menuUnmute.setVisible(false); - } else { - menuAdd.setVisible(!isConversationsOverviewHideable()); - if (this.getSelectedConversation() != null) { - if (this.getSelectedConversation().getNextEncryption() != Message.ENCRYPTION_NONE) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - menuSecure.setIcon(R.drawable.ic_lock_white_24dp); - } else { - menuSecure.setIcon(R.drawable.ic_action_secure); - } - } - if (this.getSelectedConversation().getMode() == Conversation.MODE_MULTI) { - menuContactDetails.setVisible(false); - menuAttach.setVisible(getSelectedConversation().getAccount().httpUploadAvailable() && getSelectedConversation().getMucOptions().participating()); - menuInviteContact.setVisible(getSelectedConversation().getMucOptions().canInvite()); - menuSecure.setVisible(!Config.HIDE_PGP_IN_UI); //if pgp is hidden conferences have no choice of encryption - } else { - menuMucDetails.setVisible(false); - } - if (this.getSelectedConversation().isMuted()) { - menuMute.setVisible(false); - } else { - menuUnmute.setVisible(false); - } - } - } - return true; - } - - protected void selectPresenceToAttachFile(final int attachmentChoice, final int encryption) { - final Conversation conversation = getSelectedConversation(); - final Account account = conversation.getAccount(); - final OnPresenceSelected callback = new OnPresenceSelected() { - - @Override - public void onPresenceSelected() { - Intent intent = new Intent(); - boolean chooser = false; - String fallbackPackageId = null; - switch (attachmentChoice) { - case ATTACHMENT_CHOICE_CHOOSE_IMAGE: - intent.setAction(Intent.ACTION_GET_CONTENT); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { - intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE,true); - } - intent.setType("image/*"); - chooser = true; - break; - case ATTACHMENT_CHOICE_TAKE_PHOTO: - Uri uri = xmppConnectionService.getFileBackend().getTakePhotoUri(); - intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE); - intent.putExtra(MediaStore.EXTRA_OUTPUT, uri); - mPendingImageUris.clear(); - mPendingImageUris.add(uri); - break; - case ATTACHMENT_CHOICE_CHOOSE_FILE: - chooser = true; - intent.setType("*/*"); - intent.addCategory(Intent.CATEGORY_OPENABLE); - intent.setAction(Intent.ACTION_GET_CONTENT); - break; - case ATTACHMENT_CHOICE_RECORD_VOICE: - intent.setAction(MediaStore.Audio.Media.RECORD_SOUND_ACTION); - fallbackPackageId = "eu.siacs.conversations.voicerecorder"; - break; - case ATTACHMENT_CHOICE_LOCATION: - intent.setAction("eu.siacs.conversations.location.request"); - fallbackPackageId = "eu.siacs.conversations.sharelocation"; - break; - } - if (intent.resolveActivity(getPackageManager()) != null) { - if (chooser) { - startActivityForResult( - Intent.createChooser(intent, getString(R.string.perform_action_with)), - attachmentChoice); - } else { - startActivityForResult(intent, attachmentChoice); - } - } else if (fallbackPackageId != null) { - startActivity(getInstallApkIntent(fallbackPackageId)); - } - } - }; - if ((account.httpUploadAvailable() || attachmentChoice == ATTACHMENT_CHOICE_LOCATION) && encryption != Message.ENCRYPTION_OTR) { - conversation.setNextCounterpart(null); - callback.onPresenceSelected(); - } else { - selectPresence(conversation, callback); - } - } - - private Intent getInstallApkIntent(final String packageId) { - Intent intent = new Intent(Intent.ACTION_VIEW); - intent.setData(Uri.parse("market://details?id=" + packageId)); - if (intent.resolveActivity(getPackageManager()) != null) { - return intent; - } else { - intent.setData(Uri.parse("http://play.google.com/store/apps/details?id=" + packageId)); - return intent; - } - } - - public void attachFile(final int attachmentChoice) { - switch (attachmentChoice) { - case ATTACHMENT_CHOICE_LOCATION: - getPreferences().edit().putString("recently_used_quick_action","location").apply(); - break; - case ATTACHMENT_CHOICE_RECORD_VOICE: - getPreferences().edit().putString("recently_used_quick_action","voice").apply(); - break; - case ATTACHMENT_CHOICE_TAKE_PHOTO: - getPreferences().edit().putString("recently_used_quick_action","photo").apply(); - break; - case ATTACHMENT_CHOICE_CHOOSE_IMAGE: - getPreferences().edit().putString("recently_used_quick_action","picture").apply(); - break; - } - final Conversation conversation = getSelectedConversation(); - final int encryption = conversation.getNextEncryption(); - if (encryption == Message.ENCRYPTION_PGP) { - if (hasPgp()) { - if (conversation.getContact().getPgpKeyId() != 0) { - xmppConnectionService.getPgpEngine().hasKey( - conversation.getContact(), - new UiCallback<Contact>() { - - @Override - public void userInputRequried(PendingIntent pi, - Contact contact) { - ConversationActivity.this.runIntent(pi,attachmentChoice); - } - - @Override - public void success(Contact contact) { - selectPresenceToAttachFile(attachmentChoice,encryption); - } - - @Override - public void error(int error, Contact contact) { - displayErrorDialog(error); - } - }); - } else { - final ConversationFragment fragment = (ConversationFragment) getFragmentManager() - .findFragmentByTag("conversation"); - if (fragment != null) { - fragment.showNoPGPKeyDialog(false, - new OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, - int which) { - conversation - .setNextEncryption(Message.ENCRYPTION_NONE); - xmppConnectionService.databaseBackend - .updateConversation(conversation); - selectPresenceToAttachFile(attachmentChoice,Message.ENCRYPTION_NONE); - } - }); - } - } - } else { - showInstallPgpDialog(); - } - } else { - if (encryption != Message.ENCRYPTION_AXOLOTL || !trustKeysIfNeeded(REQUEST_TRUST_KEYS_MENU, attachmentChoice)) { - selectPresenceToAttachFile(attachmentChoice, encryption); - } - } - } - - @Override - public boolean onOptionsItemSelected(final MenuItem item) { - if (item.getItemId() == android.R.id.home) { - showConversationsOverview(); - return true; - } else if (item.getItemId() == R.id.action_add) { - startActivity(new Intent(this, StartConversationActivity.class)); - return true; - } else if (getSelectedConversation() != null) { - switch (item.getItemId()) { - case R.id.action_attach_file: - attachFileDialog(); - break; - case R.id.action_archive: - this.endConversation(getSelectedConversation()); - break; - case R.id.action_contact_details: - switchToContactDetails(getSelectedConversation().getContact()); - break; - case R.id.action_muc_details: - Intent intent = new Intent(this, - ConferenceDetailsActivity.class); - intent.setAction(ConferenceDetailsActivity.ACTION_VIEW_MUC); - intent.putExtra("uuid", getSelectedConversation().getUuid()); - startActivity(intent); - break; - case R.id.action_invite: - inviteToConversation(getSelectedConversation()); - break; - case R.id.action_security: - selectEncryptionDialog(getSelectedConversation()); - break; - case R.id.action_clear_history: - clearHistoryDialog(getSelectedConversation()); - break; - case R.id.action_mute: - muteConversationDialog(getSelectedConversation()); - break; - case R.id.action_unmute: - unmuteConversation(getSelectedConversation()); - break; - case R.id.action_block: - BlockContactDialog.show(this, xmppConnectionService, getSelectedConversation()); - break; - case R.id.action_unblock: - BlockContactDialog.show(this, xmppConnectionService, getSelectedConversation()); - break; - default: - break; - } - return super.onOptionsItemSelected(item); - } else { - return super.onOptionsItemSelected(item); - } - } - - public void endConversation(Conversation conversation) { - endConversation(conversation, true, true); - } - - public void endConversation(Conversation conversation, boolean showOverview, boolean reinit) { - if (showOverview) { - showConversationsOverview(); - } - xmppConnectionService.archiveConversation(conversation); - if (reinit) { - if (conversationList.size() > 0) { - setSelectedConversation(conversationList.get(0)); - this.mConversationFragment.reInit(getSelectedConversation()); - } else { - setSelectedConversation(null); - if (mRedirected.compareAndSet(false,true)) { - Intent intent = new Intent(this, StartConversationActivity.class); - intent.putExtra("init",true); - startActivity(intent); - finish(); - } - } - } - } - - @SuppressLint("InflateParams") - protected void clearHistoryDialog(final Conversation conversation) { - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle(getString(R.string.clear_conversation_history)); - View dialogView = getLayoutInflater().inflate( - R.layout.dialog_clear_history, null); - final CheckBox endConversationCheckBox = (CheckBox) dialogView - .findViewById(R.id.end_conversation_checkbox); - builder.setView(dialogView); - builder.setNegativeButton(getString(R.string.cancel), null); - builder.setPositiveButton(getString(R.string.delete_messages), - new OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int which) { - ConversationActivity.this.xmppConnectionService.clearConversationHistory(conversation); - if (endConversationCheckBox.isChecked()) { - endConversation(conversation); - } else { - updateConversationList(); - ConversationActivity.this.mConversationFragment.updateMessages(); - } - } - }); - builder.create().show(); - } - - protected void attachFileDialog() { - View menuAttachFile = findViewById(R.id.action_attach_file); - if (menuAttachFile == null) { - return; - } - PopupMenu attachFilePopup = new PopupMenu(this, menuAttachFile); - attachFilePopup.inflate(R.menu.attachment_choices); - if (new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION).resolveActivity(getPackageManager()) == null) { - attachFilePopup.getMenu().findItem(R.id.attach_record_voice).setVisible(false); - } - if (new Intent("eu.siacs.conversations.location.request").resolveActivity(getPackageManager()) == null) { - attachFilePopup.getMenu().findItem(R.id.attach_location).setVisible(false); - } - attachFilePopup.setOnMenuItemClickListener(new OnMenuItemClickListener() { - - @Override - public boolean onMenuItemClick(MenuItem item) { - switch (item.getItemId()) { - case R.id.attach_choose_picture: - attachFile(ATTACHMENT_CHOICE_CHOOSE_IMAGE); - break; - case R.id.attach_take_picture: - attachFile(ATTACHMENT_CHOICE_TAKE_PHOTO); - break; - case R.id.attach_choose_file: - attachFile(ATTACHMENT_CHOICE_CHOOSE_FILE); - break; - case R.id.attach_record_voice: - attachFile(ATTACHMENT_CHOICE_RECORD_VOICE); - break; - case R.id.attach_location: - attachFile(ATTACHMENT_CHOICE_LOCATION); - break; - } - return false; - } - }); - attachFilePopup.show(); - } - - public void verifyOtrSessionDialog(final Conversation conversation, View view) { - if (!conversation.hasValidOtrSession() || conversation.getOtrSession().getSessionStatus() != SessionStatus.ENCRYPTED) { - Toast.makeText(this, R.string.otr_session_not_started, Toast.LENGTH_LONG).show(); - return; - } - if (view == null) { - return; - } - PopupMenu popup = new PopupMenu(this, view); - popup.inflate(R.menu.verification_choices); - popup.setOnMenuItemClickListener(new OnMenuItemClickListener() { - @Override - public boolean onMenuItemClick(MenuItem menuItem) { - Intent intent = new Intent(ConversationActivity.this, VerifyOTRActivity.class); - intent.setAction(VerifyOTRActivity.ACTION_VERIFY_CONTACT); - intent.putExtra("contact", conversation.getContact().getJid().toBareJid().toString()); - intent.putExtra("account", conversation.getAccount().getJid().toBareJid().toString()); - switch (menuItem.getItemId()) { - case R.id.scan_fingerprint: - intent.putExtra("mode", VerifyOTRActivity.MODE_SCAN_FINGERPRINT); - break; - case R.id.ask_question: - intent.putExtra("mode", VerifyOTRActivity.MODE_ASK_QUESTION); - break; - case R.id.manual_verification: - intent.putExtra("mode", VerifyOTRActivity.MODE_MANUAL_VERIFICATION); - break; - } - startActivity(intent); - return true; - } - }); - popup.show(); - } - - protected void selectEncryptionDialog(final Conversation conversation) { - View menuItemView = findViewById(R.id.action_security); - if (menuItemView == null) { - return; - } - PopupMenu popup = new PopupMenu(this, menuItemView); - final ConversationFragment fragment = (ConversationFragment) getFragmentManager() - .findFragmentByTag("conversation"); - if (fragment != null) { - popup.setOnMenuItemClickListener(new OnMenuItemClickListener() { - - @Override - public boolean onMenuItemClick(MenuItem item) { - switch (item.getItemId()) { - case R.id.encryption_choice_none: - conversation.setNextEncryption(Message.ENCRYPTION_NONE); - item.setChecked(true); - break; - case R.id.encryption_choice_otr: - conversation.setNextEncryption(Message.ENCRYPTION_OTR); - item.setChecked(true); - break; - case R.id.encryption_choice_pgp: - if (hasPgp()) { - if (conversation.getAccount().getKeys().has("pgp_signature")) { - conversation.setNextEncryption(Message.ENCRYPTION_PGP); - item.setChecked(true); - } else { - announcePgp(conversation.getAccount(),conversation); - } - } else { - showInstallPgpDialog(); - } - break; - case R.id.encryption_choice_axolotl: - Log.d(Config.LOGTAG, AxolotlService.getLogprefix(conversation.getAccount()) - + "Enabled axolotl for Contact " + conversation.getContact().getJid()); - conversation.setNextEncryption(Message.ENCRYPTION_AXOLOTL); - item.setChecked(true); - break; - default: - conversation.setNextEncryption(Message.ENCRYPTION_NONE); - break; - } - xmppConnectionService.databaseBackend.updateConversation(conversation); - fragment.updateChatMsgHint(); - invalidateOptionsMenu(); - refreshUi(); - return true; - } - }); - 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); - MenuItem pgp = popup.getMenu().findItem(R.id.encryption_choice_pgp); - MenuItem axolotl = popup.getMenu().findItem(R.id.encryption_choice_axolotl); - pgp.setVisible(!Config.HIDE_PGP_IN_UI); - if (conversation.getMode() == Conversation.MODE_MULTI) { - otr.setVisible(false); - axolotl.setVisible(false); - } else if (!conversation.getAccount().getAxolotlService().isContactAxolotlCapable(conversation.getContact())) { - axolotl.setEnabled(false); - } - switch (conversation.getNextEncryption()) { - case Message.ENCRYPTION_NONE: - none.setChecked(true); - break; - case Message.ENCRYPTION_OTR: - otr.setChecked(true); - break; - case Message.ENCRYPTION_PGP: - pgp.setChecked(true); - break; - case Message.ENCRYPTION_AXOLOTL: - axolotl.setChecked(true); - break; - default: - none.setChecked(true); - break; - } - popup.show(); - } - } - - protected void muteConversationDialog(final Conversation conversation) { - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle(R.string.disable_notifications); - final int[] durations = getResources().getIntArray(R.array.mute_options_durations); - builder.setItems(R.array.mute_options_descriptions, - new OnClickListener() { - - @Override - public void onClick(final DialogInterface dialog, final int which) { - final long till; - if (durations[which] == -1) { - till = Long.MAX_VALUE; - } else { - till = System.currentTimeMillis() + (durations[which] * 1000); - } - conversation.setMutedTill(till); - ConversationActivity.this.xmppConnectionService.databaseBackend - .updateConversation(conversation); - updateConversationList(); - ConversationActivity.this.mConversationFragment.updateMessages(); - invalidateOptionsMenu(); - } - }); - builder.create().show(); - } - - public void unmuteConversation(final Conversation conversation) { - conversation.setMutedTill(0); - this.xmppConnectionService.databaseBackend.updateConversation(conversation); - updateConversationList(); - ConversationActivity.this.mConversationFragment.updateMessages(); - invalidateOptionsMenu(); - } - - @Override - public void onBackPressed() { - if (!isConversationsOverviewVisable()) { - showConversationsOverview(); - } else { - moveTaskToBack(true); - } - } - - @Override - public boolean onKeyUp(int key, KeyEvent event) { - int rotation = getWindowManager().getDefaultDisplay().getRotation(); - final int upKey; - final int downKey; - switch(rotation) { - case Surface.ROTATION_90: - upKey = KeyEvent.KEYCODE_DPAD_LEFT; - downKey = KeyEvent.KEYCODE_DPAD_RIGHT; - break; - case Surface.ROTATION_180: - upKey = KeyEvent.KEYCODE_DPAD_DOWN; - downKey = KeyEvent.KEYCODE_DPAD_UP; - break; - case Surface.ROTATION_270: - upKey = KeyEvent.KEYCODE_DPAD_RIGHT; - downKey = KeyEvent.KEYCODE_DPAD_LEFT; - break; - default: - upKey = KeyEvent.KEYCODE_DPAD_UP; - downKey = KeyEvent.KEYCODE_DPAD_DOWN; - } - final boolean modifier = event.isCtrlPressed() || event.isAltPressed(); - if (modifier && key == KeyEvent.KEYCODE_TAB && isConversationsOverviewHideable()) { - toggleConversationsOverview(); - return true; - } else if (modifier && key == downKey) { - if (isConversationsOverviewHideable() && !isConversationsOverviewVisable()) { - showConversationsOverview();; - } - return selectDownConversation(); - } else if (modifier && key == upKey) { - if (isConversationsOverviewHideable() && !isConversationsOverviewVisable()) { - showConversationsOverview(); - } - return selectUpConversation(); - } else if (modifier && key == KeyEvent.KEYCODE_1) { - return openConversationByIndex(0); - } else if (modifier && key == KeyEvent.KEYCODE_2) { - return openConversationByIndex(1); - } else if (modifier && key == KeyEvent.KEYCODE_3) { - return openConversationByIndex(2); - } else if (modifier && key == KeyEvent.KEYCODE_4) { - return openConversationByIndex(3); - } else if (modifier && key == KeyEvent.KEYCODE_5) { - return openConversationByIndex(4); - } else if (modifier && key == KeyEvent.KEYCODE_6) { - return openConversationByIndex(5); - } else if (modifier && key == KeyEvent.KEYCODE_7) { - return openConversationByIndex(6); - } else if (modifier && key == KeyEvent.KEYCODE_8) { - return openConversationByIndex(7); - } else if (modifier && key == KeyEvent.KEYCODE_9) { - return openConversationByIndex(8); - } else if (modifier && key == KeyEvent.KEYCODE_0) { - return openConversationByIndex(9); - } else { - return super.onKeyUp(key, event); - } - } - - private void toggleConversationsOverview() { - if (isConversationsOverviewVisable()) { - hideConversationsOverview(); - if (mConversationFragment != null) { - mConversationFragment.setFocusOnInputField(); - } - } else { - showConversationsOverview(); - } - } - - private boolean selectUpConversation() { - if (this.mSelectedConversation != null) { - int index = this.conversationList.indexOf(this.mSelectedConversation); - if (index > 0) { - return openConversationByIndex(index - 1); - } - } - return false; - } - - private boolean selectDownConversation() { - if (this.mSelectedConversation != null) { - int index = this.conversationList.indexOf(this.mSelectedConversation); - if (index != -1 && index < this.conversationList.size() - 1) { - return openConversationByIndex(index + 1); - } - } - return false; - } - - private boolean openConversationByIndex(int index) { - try { - this.conversationWasSelectedByKeyboard = true; - setSelectedConversation(this.conversationList.get(index)); - this.mConversationFragment.reInit(getSelectedConversation()); - if (index > listView.getLastVisiblePosition() - 1 || index < listView.getFirstVisiblePosition() + 1) { - this.listView.setSelection(index); - } - openConversation(); - return true; - } catch (IndexOutOfBoundsException e) { - return false; - } - } - - @Override - protected void onNewIntent(final Intent intent) { - if (xmppConnectionServiceBound) { - if (intent != null && VIEW_CONVERSATION.equals(intent.getType())) { - handleViewConversationIntent(intent); - } - } else { - setIntent(intent); - } - } - - @Override - public void onStart() { - super.onStart(); - this.mRedirected.set(false); - if (this.xmppConnectionServiceBound) { - this.onBackendConnected(); - } - if (conversationList.size() >= 1) { - this.onConversationUpdate(); - } - } - - @Override - public void onPause() { - listView.discardUndo(); - super.onPause(); - this.mActivityPaused = true; - if (this.xmppConnectionServiceBound) { - this.xmppConnectionService.getNotificationService().setIsInForeground(false); - } - } - - @Override - public void onResume() { - super.onResume(); - final int theme = findTheme(); - final boolean usingEnterKey = usingEnterKey(); - if (this.mTheme != theme || usingEnterKey != mUsingEnterKey) { - recreate(); - } - this.mActivityPaused = false; - if (this.xmppConnectionServiceBound) { - this.xmppConnectionService.getNotificationService().setIsInForeground(true); - } - - if (!isConversationsOverviewVisable() || !isConversationsOverviewHideable()) { - sendReadMarkerIfNecessary(getSelectedConversation()); - } - - } - - @Override - public void onSaveInstanceState(final Bundle savedInstanceState) { - Conversation conversation = getSelectedConversation(); - if (conversation != null) { - savedInstanceState.putString(STATE_OPEN_CONVERSATION, - conversation.getUuid()); - } - savedInstanceState.putBoolean(STATE_PANEL_OPEN, - isConversationsOverviewVisable()); - if (this.mPendingImageUris.size() >= 1) { - savedInstanceState.putString(STATE_PENDING_URI, this.mPendingImageUris.get(0).toString()); - } - super.onSaveInstanceState(savedInstanceState); - } - - @Override - void onBackendConnected() { - this.xmppConnectionService.getNotificationService().setIsInForeground(true); - updateConversationList(); - - if (mPendingConferenceInvite != null) { - mPendingConferenceInvite.execute(this); - mPendingConferenceInvite = null; - } - - if (xmppConnectionService.getAccounts().size() == 0) { - if (mRedirected.compareAndSet(false,true)) { - if (Config.X509_VERIFICATION) { - startActivity(new Intent(this, ManageAccountActivity.class)); - } else { - startActivity(new Intent(this, EditAccountActivity.class)); - } - finish(); - } - } else if (conversationList.size() <= 0) { - if (mRedirected.compareAndSet(false,true)) { - Intent intent = new Intent(this, StartConversationActivity.class); - intent.putExtra("init",true); - startActivity(intent); - finish(); - } - } else if (getIntent() != null && VIEW_CONVERSATION.equals(getIntent().getType())) { - handleViewConversationIntent(getIntent()); - } else if (selectConversationByUuid(mOpenConverstaion)) { - if (mPanelOpen) { - showConversationsOverview(); - } else { - if (isConversationsOverviewHideable()) { - openConversation(); - } - } - this.mConversationFragment.reInit(getSelectedConversation()); - mOpenConverstaion = null; - } else if (getSelectedConversation() == null) { - showConversationsOverview(); - mPendingImageUris.clear(); - mPendingFileUris.clear(); - mPendingGeoUri = null; - setSelectedConversation(conversationList.get(0)); - this.mConversationFragment.reInit(getSelectedConversation()); - } else { - this.mConversationFragment.messageListAdapter.updatePreferences(); - this.mConversationFragment.messagesView.invalidateViews(); - this.mConversationFragment.setupIme(); - } - - if(!forbidProcessingPendings) { - for (Iterator<Uri> i = mPendingImageUris.iterator(); i.hasNext(); i.remove()) { - Uri foo = i.next(); - attachImageToConversation(getSelectedConversation(), foo); - } - - for (Iterator<Uri> i = mPendingFileUris.iterator(); i.hasNext(); i.remove()) { - attachFileToConversation(getSelectedConversation(), i.next()); - } - - if (mPendingGeoUri != null) { - attachLocationToConversation(getSelectedConversation(), mPendingGeoUri); - mPendingGeoUri = null; - } - } - forbidProcessingPendings = false; - - ExceptionHelper.checkForCrash(this, this.xmppConnectionService); - setIntent(new Intent()); - } - - private void handleViewConversationIntent(final Intent intent) { - final String uuid = intent.getStringExtra(CONVERSATION); - final String downloadUuid = intent.getStringExtra(MESSAGE); - final String text = intent.getStringExtra(TEXT); - final String nick = intent.getStringExtra(NICK); - final boolean pm = intent.getBooleanExtra(PRIVATE_MESSAGE,false); - if (selectConversationByUuid(uuid)) { - this.mConversationFragment.reInit(getSelectedConversation()); - if (nick != null) { - if (pm) { - Jid jid = getSelectedConversation().getJid(); - try { - Jid next = Jid.fromParts(jid.getLocalpart(),jid.getDomainpart(),nick); - this.mConversationFragment.privateMessageWith(next); - } catch (final InvalidJidException ignored) { - //do nothing - } - } else { - this.mConversationFragment.highlightInConference(nick); - } - } else { - this.mConversationFragment.appendText(text); - } - hideConversationsOverview(); - openConversation(); - if (mContentView instanceof SlidingPaneLayout) { - updateActionBarTitle(true); //fixes bug where slp isn't properly closed yet - } - if (downloadUuid != null) { - final Message message = mSelectedConversation.findMessageWithFileAndUuid(downloadUuid); - if (message != null) { - mConversationFragment.messageListAdapter.startDownloadable(message); - } - } - } - } - - private boolean selectConversationByUuid(String uuid) { - if (uuid == null) { - return false; - } - for (Conversation aConversationList : conversationList) { - if (aConversationList.getUuid().equals(uuid)) { - setSelectedConversation(aConversationList); - return true; - } - } - return false; - } - - @Override - protected void unregisterListeners() { - super.unregisterListeners(); - xmppConnectionService.getNotificationService().setOpenConversation(null); - } - - @SuppressLint("NewApi") - private static List<Uri> extractUriFromIntent(final Intent intent) { - List<Uri> uris = new ArrayList<>(); - Uri uri = intent.getData(); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2 && uri == null) { - ClipData clipData = intent.getClipData(); - for(int i = 0; i < clipData.getItemCount(); ++i) { - uris.add(clipData.getItemAt(i).getUri()); - } - } else { - uris.add(uri); - } - return uris; - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, - final Intent data) { - super.onActivityResult(requestCode, resultCode, data); - if (resultCode == RESULT_OK) { - if (requestCode == REQUEST_DECRYPT_PGP) { - mConversationFragment.onActivityResult(requestCode, resultCode, data); - } else if (requestCode == ATTACHMENT_CHOICE_CHOOSE_IMAGE) { - mPendingImageUris.clear(); - mPendingImageUris.addAll(extractUriFromIntent(data)); - if (xmppConnectionServiceBound) { - for(Iterator<Uri> i = mPendingImageUris.iterator(); i.hasNext(); i.remove()) { - attachImageToConversation(getSelectedConversation(),i.next()); - } - } - } else if (requestCode == ATTACHMENT_CHOICE_CHOOSE_FILE || requestCode == ATTACHMENT_CHOICE_RECORD_VOICE) { - mPendingFileUris.clear(); - mPendingFileUris.addAll(extractUriFromIntent(data)); - if (xmppConnectionServiceBound) { - for(Iterator<Uri> i = mPendingFileUris.iterator(); i.hasNext(); i.remove()) { - attachFileToConversation(getSelectedConversation(), i.next()); - } - } - } else if (requestCode == ATTACHMENT_CHOICE_TAKE_PHOTO) { - if (mPendingImageUris.size() == 1) { - Uri uri = mPendingImageUris.get(0); - if (xmppConnectionServiceBound) { - attachImageToConversation(getSelectedConversation(), uri); - mPendingImageUris.clear(); - } - Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE); - intent.setData(uri); - sendBroadcast(intent); - } else { - mPendingImageUris.clear(); - } - } else if (requestCode == ATTACHMENT_CHOICE_LOCATION) { - double latitude = data.getDoubleExtra("latitude",0); - double longitude = data.getDoubleExtra("longitude",0); - this.mPendingGeoUri = Uri.parse("geo:"+String.valueOf(latitude)+","+String.valueOf(longitude)); - if (xmppConnectionServiceBound) { - attachLocationToConversation(getSelectedConversation(), mPendingGeoUri); - this.mPendingGeoUri = null; - } - } else if (requestCode == REQUEST_TRUST_KEYS_TEXT || requestCode == REQUEST_TRUST_KEYS_MENU) { - this.forbidProcessingPendings = !xmppConnectionServiceBound; - mConversationFragment.onActivityResult(requestCode, resultCode, data); - } - } else { - mPendingImageUris.clear(); - mPendingFileUris.clear(); - if (requestCode == ConversationActivity.REQUEST_DECRYPT_PGP) { - mConversationFragment.onActivityResult(requestCode, resultCode, data); - } - } - } - - private void attachLocationToConversation(Conversation conversation, Uri uri) { - if (conversation == null) { - return; - } - xmppConnectionService.attachLocationToConversation(conversation,uri, new UiCallback<Message>() { - - @Override - public void success(Message message) { - xmppConnectionService.sendMessage(message); - } - - @Override - public void error(int errorCode, Message object) { - - } - - @Override - public void userInputRequried(PendingIntent pi, Message object) { - - } - }); - } - - private void attachFileToConversation(Conversation conversation, Uri uri) { - if (conversation == null) { - return; - } - prepareFileToast = Toast.makeText(getApplicationContext(),getText(R.string.preparing_file), Toast.LENGTH_LONG); - prepareFileToast.show(); - xmppConnectionService.attachFileToConversation(conversation, uri, new UiCallback<Message>() { - @Override - public void success(Message message) { - hidePrepareFileToast(); - xmppConnectionService.sendMessage(message); - } - - @Override - public void error(int errorCode, Message message) { - displayErrorDialog(errorCode); - } - - @Override - public void userInputRequried(PendingIntent pi, Message message) { - - } - }); - } - - private void attachImageToConversation(Conversation conversation, Uri uri) { - if (conversation == null) { - return; - } - prepareFileToast = Toast.makeText(getApplicationContext(),getText(R.string.preparing_image), Toast.LENGTH_LONG); - prepareFileToast.show(); - xmppConnectionService.attachImageToConversation(conversation, uri, - new UiCallback<Message>() { - - @Override - public void userInputRequried(PendingIntent pi, - Message object) { - hidePrepareFileToast(); - } - - @Override - public void success(Message message) { - xmppConnectionService.sendMessage(message); - } - - @Override - public void error(int error, Message message) { - hidePrepareFileToast(); - displayErrorDialog(error); - } - }); - } - - private void hidePrepareFileToast() { - if (prepareFileToast != null) { - runOnUiThread(new Runnable() { - - @Override - public void run() { - prepareFileToast.cancel(); - } - }); - } - } - - public void updateConversationList() { - xmppConnectionService - .populateWithOrderedConversations(conversationList); - if (swipedConversation != null) { - if (swipedConversation.isRead()) { - conversationList.remove(swipedConversation); - } else { - listView.discardUndo(); - } - } - listAdapter.notifyDataSetChanged(); - } - - public void runIntent(PendingIntent pi, int requestCode) { - try { - this.startIntentSenderForResult(pi.getIntentSender(), requestCode, - null, 0, 0, 0); - } catch (final SendIntentException ignored) { - } - } - - public void encryptTextMessage(Message message) { - xmppConnectionService.getPgpEngine().encrypt(message, - new UiCallback<Message>() { - - @Override - public void userInputRequried(PendingIntent pi, - Message message) { - ConversationActivity.this.runIntent(pi, - ConversationActivity.REQUEST_SEND_MESSAGE); - } - - @Override - public void success(Message message) { - message.setEncryption(Message.ENCRYPTION_DECRYPTED); - xmppConnectionService.sendMessage(message); - } - - @Override - public void error(int error, Message message) { - - } - }); - } - - public boolean useSendButtonToIndicateStatus() { - return getPreferences().getBoolean("send_button_status", false); - } - - public boolean indicateReceived() { - return getPreferences().getBoolean("indicate_received", false); - } - - public boolean useWhiteBackground() { - return getPreferences().getBoolean("use_white_background",false); - } - - protected boolean trustKeysIfNeeded(int requestCode) { - return trustKeysIfNeeded(requestCode, ATTACHMENT_CHOICE_INVALID); - } - - protected boolean trustKeysIfNeeded(int requestCode, int attachmentChoice) { - AxolotlService axolotlService = mSelectedConversation.getAccount().getAxolotlService(); - boolean hasPendingKeys = !axolotlService.getKeysWithTrust(XmppAxolotlSession.Trust.UNDECIDED, - mSelectedConversation.getContact()).isEmpty() - || !axolotlService.findDevicesWithoutSession(mSelectedConversation).isEmpty(); - boolean hasNoTrustedKeys = axolotlService.getNumTrustedKeys(mSelectedConversation.getContact()) == 0; - if( hasPendingKeys || hasNoTrustedKeys) { - axolotlService.createSessionsIfNeeded(mSelectedConversation); - Intent intent = new Intent(getApplicationContext(), TrustKeysActivity.class); - intent.putExtra("contact", mSelectedConversation.getContact().getJid().toBareJid().toString()); - intent.putExtra("account", mSelectedConversation.getAccount().getJid().toBareJid().toString()); - intent.putExtra("choice", attachmentChoice); - intent.putExtra("has_no_trusted", hasNoTrustedKeys); - startActivityForResult(intent, requestCode); - return true; - } else { - return false; - } - } - - @Override - protected void refreshUiReal() { - updateConversationList(); - if (conversationList.size() > 0) { - ConversationActivity.this.mConversationFragment.updateMessages(); - updateActionBarTitle(); - invalidateOptionsMenu(); - } - } - - @Override - public void onAccountUpdate() { - this.refreshUi(); - } - - @Override - public void onConversationUpdate() { - this.refreshUi(); - } - - @Override - public void onRosterUpdate() { - this.refreshUi(); - } - - @Override - public void OnUpdateBlocklist(Status status) { - this.refreshUi(); - } - - public void unblockConversation(final Blockable conversation) { - xmppConnectionService.sendUnblockRequest(conversation); - } - - public boolean enterIsSend() { - return getPreferences().getBoolean("enter_is_send",false); - } - - @Override - public void onShowErrorToast(final int resId) { - runOnUiThread(new Runnable() { - @Override - public void run() { - Toast.makeText(ConversationActivity.this,resId,Toast.LENGTH_SHORT).show(); - } - }); - } - - public boolean highlightSelectedConversations() { - return !isConversationsOverviewHideable() || this.conversationWasSelectedByKeyboard; - } +implements OnAccountUpdate, OnConversationUpdate, OnRosterUpdate, OnUpdateBlocklist, XmppConnectionService.OnShowErrorToast { + + public static final String ACTION_DOWNLOAD = "eu.siacs.conversations.action.DOWNLOAD"; + + public static final String VIEW_CONVERSATION = "viewConversation"; + public static final String CONVERSATION = "conversationUuid"; + public static final String MESSAGE = "messageUuid"; + public static final String TEXT = "text"; + public static final String NICK = "nick"; + public static final String PRIVATE_MESSAGE = "pm"; + + public static final int REQUEST_SEND_MESSAGE = 0x0201; + public static final int REQUEST_DECRYPT_PGP = 0x0202; + public static final int REQUEST_ENCRYPT_MESSAGE = 0x0207; + public static final int REQUEST_TRUST_KEYS_TEXT = 0x0208; + public static final int REQUEST_TRUST_KEYS_MENU = 0x0209; + public static final int ATTACHMENT_CHOICE_CHOOSE_IMAGE = 0x0301; + public static final int ATTACHMENT_CHOICE_TAKE_PHOTO = 0x0302; + public static final int ATTACHMENT_CHOICE_CHOOSE_FILE = 0x0303; + public static final int ATTACHMENT_CHOICE_RECORD_VOICE = 0x0304; + public static final int ATTACHMENT_CHOICE_LOCATION = 0x0305; + public static final int ATTACHMENT_CHOICE_INVALID = 0x0306; + private static final String STATE_OPEN_CONVERSATION = "state_open_conversation"; + private static final String STATE_PANEL_OPEN = "state_panel_open"; + private static final String STATE_PENDING_URI = "state_pending_uri"; + + private String mOpenConverstaion = null; + private boolean mPanelOpen = true; + final private List<Uri> mPendingImageUris = new ArrayList<>(); + final private List<Uri> mPendingFileUris = new ArrayList<>(); + private Uri mPendingGeoUri = null; + private boolean forbidProcessingPendings = false; + + private boolean conversationWasSelectedByKeyboard = false; + + private View mContentView; + + private List<Conversation> conversationList = new ArrayList<>(); + private Conversation swipedConversation = null; + private Conversation mSelectedConversation = null; + private EnhancedListView listView; + private ConversationFragment mConversationFragment; + + private ArrayAdapter<Conversation> listAdapter; + + private Toast prepareFileToast; + + private boolean mActivityPaused = false; + private AtomicBoolean mRedirected = new AtomicBoolean(false); + + public Conversation getSelectedConversation() { + return this.mSelectedConversation; + } + + public void setSelectedConversation(Conversation conversation) { + this.mSelectedConversation = conversation; + } + + public void showConversationsOverview() { + if (mContentView instanceof SlidingPaneLayout) { + SlidingPaneLayout mSlidingPaneLayout = (SlidingPaneLayout) mContentView; + mSlidingPaneLayout.openPane(); + } + } + + @Override + protected String getShareableUri() { + Conversation conversation = getSelectedConversation(); + if (conversation != null) { + return conversation.getAccount().getShareableUri(); + } else { + return ""; + } + } + + public void hideConversationsOverview() { + if (mContentView instanceof SlidingPaneLayout) { + SlidingPaneLayout mSlidingPaneLayout = (SlidingPaneLayout) mContentView; + mSlidingPaneLayout.closePane(); + } + } + + public boolean isConversationsOverviewHideable() { + if (mContentView instanceof SlidingPaneLayout) { + SlidingPaneLayout mSlidingPaneLayout = (SlidingPaneLayout) mContentView; + return mSlidingPaneLayout.isSlideable(); + } else { + return false; + } + } + + public boolean isConversationsOverviewVisable() { + if (mContentView instanceof SlidingPaneLayout) { + SlidingPaneLayout mSlidingPaneLayout = (SlidingPaneLayout) mContentView; + return mSlidingPaneLayout.isOpen(); + } else { + return true; + } + } + + @Override + protected void onCreate(final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (savedInstanceState != null) { + mOpenConverstaion = savedInstanceState.getString(STATE_OPEN_CONVERSATION, null); + mPanelOpen = savedInstanceState.getBoolean(STATE_PANEL_OPEN, true); + String pending = savedInstanceState.getString(STATE_PENDING_URI, null); + if (pending != null) { + mPendingImageUris.clear(); + mPendingImageUris.add(Uri.parse(pending)); + } + } + + AppUpdate(); + + setContentView(R.layout.fragment_conversations_overview); + + this.mConversationFragment = new ConversationFragment(); + FragmentTransaction transaction = getFragmentManager().beginTransaction(); + transaction.replace(R.id.selected_conversation, this.mConversationFragment, "conversation"); + transaction.commit(); + + listView = (EnhancedListView) findViewById(R.id.list); + this.listAdapter = new ConversationAdapter(this, conversationList); + listView.setAdapter(this.listAdapter); + + if (getActionBar() != null) { + getActionBar().setDisplayHomeAsUpEnabled(false); + getActionBar().setHomeButtonEnabled(false); + } + + listView.setOnItemClickListener(new OnItemClickListener() { + + @Override + public void onItemClick(AdapterView<?> arg0, View clickedView, + int position, long arg3) { + if (getSelectedConversation() != conversationList.get(position)) { + setSelectedConversation(conversationList.get(position)); + ConversationActivity.this.mConversationFragment.reInit(getSelectedConversation()); + conversationWasSelectedByKeyboard = false; + } + hideConversationsOverview(); + openConversation(); + } + }); + + listView.setDismissCallback(new EnhancedListView.OnDismissCallback() { + @Override + public EnhancedListView.Undoable onDismiss(final EnhancedListView enhancedListView, final int position) { + + final int index = listView.getFirstVisiblePosition(); + View v = listView.getChildAt(0); + final int top = (v == null) ? 0 : (v.getTop() - listView.getPaddingTop()); + + try { + swipedConversation = listAdapter.getItem(position); + } catch (IndexOutOfBoundsException e) { + return null; + } + listAdapter.remove(swipedConversation); + xmppConnectionService.markRead(swipedConversation); + + final boolean formerlySelected = (getSelectedConversation() == swipedConversation); + if (position == 0 && listAdapter.getCount() == 0) { + endConversation(swipedConversation, false, true); + return null; + } else if (formerlySelected) { + setSelectedConversation(listAdapter.getItem(0)); + ConversationActivity.this.mConversationFragment + .reInit(getSelectedConversation()); + } + + return new EnhancedListView.Undoable() { + + @Override + public void undo() { + listAdapter.insert(swipedConversation, position); + if (formerlySelected) { + setSelectedConversation(swipedConversation); + ConversationActivity.this.mConversationFragment + .reInit(getSelectedConversation()); + } + swipedConversation = null; + listView.setSelectionFromTop(index + (listView.getChildCount() < position ? 1 : 0), top); + } + + @Override + public void discard() { + if (!swipedConversation.isRead() + && swipedConversation.getMode() == Conversation.MODE_SINGLE) { + swipedConversation = null; + return; + } + endConversation(swipedConversation, false, false); + swipedConversation = null; + } + + @Override + public String getTitle() { + if (swipedConversation.getMode() == Conversation.MODE_MULTI) { + return getResources().getString(R.string.title_undo_swipe_out_muc); + } else { + return getResources().getString(R.string.title_undo_swipe_out_conversation); + } + } + }; + } + }); + listView.enableSwipeToDismiss(); + listView.setSwipingLayout(R.id.swipeable_item); + listView.setUndoStyle(EnhancedListView.UndoStyle.SINGLE_POPUP); + listView.setUndoHideDelay(10000); + listView.setRequireTouchBeforeDismiss(false); + listView.setSwipeDirection(EnhancedListView.SwipeDirection.START); // swipe to left to close conversation + + mContentView = findViewById(R.id.content_view_spl); + if (mContentView == null) { + mContentView = findViewById(R.id.content_view_ll); + } + if (mContentView instanceof SlidingPaneLayout) { + SlidingPaneLayout mSlidingPaneLayout = (SlidingPaneLayout) mContentView; + mSlidingPaneLayout.setParallaxDistance(150); + mSlidingPaneLayout + .setShadowResource(R.drawable.es_slidingpane_shadow); + mSlidingPaneLayout.setSliderFadeColor(0); + mSlidingPaneLayout.setPanelSlideListener(new PanelSlideListener() { + + @Override + public void onPanelOpened(View arg0) { + updateActionBarTitle(); + invalidateOptionsMenu(); + hideKeyboard(); + if (xmppConnectionServiceBound) { + xmppConnectionService.getNotificationService() + .setOpenConversation(null); + } + closeContextMenu(); + } + + @Override + public void onPanelClosed(View arg0) { + listView.discardUndo(); + openConversation(); + } + + @Override + public void onPanelSlide(View arg0, float arg1) { + // TODO Auto-generated method stub + + } + }); + } + } + + protected void AppUpdate() { + String PREFS_NAME = "UpdateTimeStamp"; + SharedPreferences UpdateTimeStamp = getApplicationContext().getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE); + long lastUpdateTime = UpdateTimeStamp.getLong("lastUpdateTime", 0); + + Log.d(Config.LOGTAG, "AppUpdater - LastUpdateTime: " + lastUpdateTime); + + if ((lastUpdateTime + (Config.UPDATE_CHECK_TIMER * 1000)) < System.currentTimeMillis()) { + lastUpdateTime = System.currentTimeMillis(); + SharedPreferences.Editor editor = UpdateTimeStamp.edit(); + editor.putLong("lastUpdateTime", lastUpdateTime); + editor.commit(); + + // run AppUpdater + Log.d(Config.LOGTAG, "AppUpdater - CurrentTime: " + lastUpdateTime); + Intent AppUpdater = new Intent(this, UpdaterActivity.class); + startActivity(AppUpdater); + Log.d(Config.LOGTAG, "AppUpdater started"); + + } else { + + Log.d(Config.LOGTAG, "AppUpdater stopped"); + return; + } + } + + @Override + public void switchToConversation(Conversation conversation) { + setSelectedConversation(conversation); + runOnUiThread(new Runnable() { + @Override + public void run() { + ConversationActivity.this.mConversationFragment.reInit(getSelectedConversation()); + openConversation(); + } + }); + } + + private void updateActionBarTitle() { + updateActionBarTitle(isConversationsOverviewHideable() && !isConversationsOverviewVisable()); + } + + private void updateActionBarTitle(boolean titleShouldBeName) { + final ActionBar ab = getActionBar(); + final Conversation conversation = getSelectedConversation(); + if (ab != null) { + if (titleShouldBeName && conversation != null) { + ab.setDisplayHomeAsUpEnabled(true); + ab.setHomeButtonEnabled(true); + if (conversation.getMode() == Conversation.MODE_SINGLE || useSubjectToIdentifyConference()) { + ab.setTitle(conversation.getName()); + if (conversation.getMode() == Conversation.MODE_SINGLE) { + if (conversation.getContact().getPresences().getMostAvailableStatus() == Presences.OFFLINE) { + ab.setSubtitle(getString(R.string.account_status_offline)); + } else { + ChatState state = conversation.getIncomingChatState(); + if (state == ChatState.COMPOSING) { + ab.setSubtitle(getString(R.string.is_typing)); + } else if (state == ChatState.PAUSED) { + ab.setSubtitle(UIHelper.lastseen(getApplicationContext(), conversation.getContact().lastseen.time)); + } else { + ab.setSubtitle(UIHelper.lastseen(getApplicationContext(), conversation.getContact().lastseen.time)); + } + } + } else if (useSubjectToIdentifyConference()) { + ab.setSubtitle(conversation.getParticipants()); + } + } else { + ab.setTitle(conversation.getJid().toBareJid().toString()); + ab.setSubtitle(null); + } + } else { + ab.setDisplayHomeAsUpEnabled(false); + ab.setHomeButtonEnabled(false); + ab.setTitle(R.string.app_name); + ab.setSubtitle(null); + } + } + } + + private void openConversation() { + this.updateActionBarTitle(); + this.invalidateOptionsMenu(); + if (xmppConnectionServiceBound) { + final Conversation conversation = getSelectedConversation(); + xmppConnectionService.getNotificationService().setOpenConversation(conversation); + sendReadMarkerIfNecessary(conversation); + } + listAdapter.notifyDataSetChanged(); + } + + public void sendReadMarkerIfNecessary(final Conversation conversation) { + if (!mActivityPaused && conversation != null) { + if (!conversation.isRead()) { + xmppConnectionService.sendReadMarker(conversation); + } else { + xmppConnectionService.markRead(conversation); + } + } + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.conversations, menu); + final MenuItem menuSecure = menu.findItem(R.id.action_security); + final MenuItem menuArchive = menu.findItem(R.id.action_archive); + final MenuItem menuMucDetails = menu.findItem(R.id.action_muc_details); + final MenuItem menuContactDetails = menu.findItem(R.id.action_contact_details); + final MenuItem menuAttach = menu.findItem(R.id.action_attach_file); + final MenuItem menuClearHistory = menu.findItem(R.id.action_clear_history); + final MenuItem menuAdd = menu.findItem(R.id.action_add); + final MenuItem menuInviteContact = menu.findItem(R.id.action_invite); + final MenuItem menuMute = menu.findItem(R.id.action_mute); + final MenuItem menuUnmute = menu.findItem(R.id.action_unmute); + + if (isConversationsOverviewVisable() && isConversationsOverviewHideable()) { + menuArchive.setVisible(false); + menuMucDetails.setVisible(false); + menuContactDetails.setVisible(false); + menuSecure.setVisible(false); + menuInviteContact.setVisible(false); + menuAttach.setVisible(false); + menuClearHistory.setVisible(false); + menuMute.setVisible(false); + menuUnmute.setVisible(false); + } else { + menuAdd.setVisible(!isConversationsOverviewHideable()); + if (this.getSelectedConversation() != null) { + menuSecure.setVisible(!Config.HIDE_ENCRYPTION_IN_UI); + if (this.getSelectedConversation().getNextEncryption() != Message.ENCRYPTION_NONE) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + menuSecure.setIcon(R.drawable.ic_lock_white_24dp); + } else { + menuSecure.setIcon(R.drawable.ic_action_secure); + } + } + if (this.getSelectedConversation().getMode() == Conversation.MODE_MULTI) { + menuContactDetails.setVisible(false); + menuAttach.setVisible(getSelectedConversation().getAccount().httpUploadAvailable() && getSelectedConversation().getMucOptions().participating()); + menuInviteContact.setVisible(getSelectedConversation().getMucOptions().canInvite()); + menuSecure.setVisible(!Config.HIDE_ENCRYPTION_IN_UI); + menuSecure.setVisible(!Config.HIDE_PGP_IN_UI); //if pgp is hidden conferences have no choice of encryption + } else { + menuMucDetails.setVisible(false); + } + if (this.getSelectedConversation().isMuted()) { + menuMute.setVisible(false); + } else { + menuUnmute.setVisible(false); + } + } + } + return true; + } + + protected void selectPresenceToAttachFile(final int attachmentChoice, final int encryption) { + final Conversation conversation = getSelectedConversation(); + final Account account = conversation.getAccount(); + final OnPresenceSelected callback = new OnPresenceSelected() { + + @Override + public void onPresenceSelected() { + Intent intent = new Intent(); + boolean chooser = false; + String fallbackPackageId = null; + switch (attachmentChoice) { + case ATTACHMENT_CHOICE_CHOOSE_IMAGE: + intent.setAction(Intent.ACTION_GET_CONTENT); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { + intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true); + } + intent.setType("image/*"); + chooser = true; + break; + case ATTACHMENT_CHOICE_TAKE_PHOTO: + Uri uri = xmppConnectionService.getFileBackend().getTakePhotoUri(); + intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE); + intent.putExtra(MediaStore.EXTRA_OUTPUT, uri); + mPendingImageUris.clear(); + mPendingImageUris.add(uri); + break; + case ATTACHMENT_CHOICE_CHOOSE_FILE: + chooser = true; + intent.setType("*/*"); + intent.addCategory(Intent.CATEGORY_OPENABLE); + intent.setAction(Intent.ACTION_GET_CONTENT); + break; + case ATTACHMENT_CHOICE_RECORD_VOICE: + intent.setAction(MediaStore.Audio.Media.RECORD_SOUND_ACTION); + fallbackPackageId = "eu.siacs.conversations.voicerecorder"; + break; + case ATTACHMENT_CHOICE_LOCATION: + intent.setAction("eu.siacs.conversations.location.request"); + fallbackPackageId = "eu.siacs.conversations.sharelocation"; + break; + } + if (intent.resolveActivity(getPackageManager()) != null) { + if (chooser) { + startActivityForResult( + Intent.createChooser(intent, getString(R.string.perform_action_with)), + attachmentChoice); + } else { + startActivityForResult(intent, attachmentChoice); + } + } else if (fallbackPackageId != null) { + startActivity(getInstallApkIntent(fallbackPackageId)); + } + } + }; + if ((account.httpUploadAvailable() || attachmentChoice == ATTACHMENT_CHOICE_LOCATION) && encryption != Message.ENCRYPTION_OTR) { + conversation.setNextCounterpart(null); + callback.onPresenceSelected(); + } else { + selectPresence(conversation, callback); + } + } + + private Intent getInstallApkIntent(final String packageId) { + Intent intent = new Intent(Intent.ACTION_VIEW); + intent.setData(Uri.parse("market://details?id=" + packageId)); + if (intent.resolveActivity(getPackageManager()) != null) { + return intent; + } else { + intent.setData(Uri.parse("http://play.google.com/store/apps/details?id=" + packageId)); + return intent; + } + } + + public void attachFile(final int attachmentChoice) { + switch (attachmentChoice) { + case ATTACHMENT_CHOICE_LOCATION: + getPreferences().edit().putString("recently_used_quick_action", "location").apply(); + break; + case ATTACHMENT_CHOICE_RECORD_VOICE: + getPreferences().edit().putString("recently_used_quick_action", "voice").apply(); + break; + case ATTACHMENT_CHOICE_TAKE_PHOTO: + getPreferences().edit().putString("recently_used_quick_action", "photo").apply(); + break; + case ATTACHMENT_CHOICE_CHOOSE_IMAGE: + getPreferences().edit().putString("recently_used_quick_action", "picture").apply(); + break; + } + final Conversation conversation = getSelectedConversation(); + final int encryption = conversation.getNextEncryption(); + if (encryption == Message.ENCRYPTION_PGP) { + if (hasPgp()) { + if (conversation.getContact().getPgpKeyId() != 0) { + xmppConnectionService.getPgpEngine().hasKey( + conversation.getContact(), + new UiCallback<Contact>() { + + @Override + public void userInputRequried(PendingIntent pi, + Contact contact) { + ConversationActivity.this.runIntent(pi, attachmentChoice); + } + + @Override + public void success(Contact contact) { + selectPresenceToAttachFile(attachmentChoice, encryption); + } + + @Override + public void error(int error, Contact contact) { + displayErrorDialog(error); + } + }); + } else { + final ConversationFragment fragment = (ConversationFragment) getFragmentManager() + .findFragmentByTag("conversation"); + if (fragment != null) { + fragment.showNoPGPKeyDialog(false, + new OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, + int which) { + conversation + .setNextEncryption(Message.ENCRYPTION_NONE); + xmppConnectionService.databaseBackend + .updateConversation(conversation); + selectPresenceToAttachFile(attachmentChoice, Message.ENCRYPTION_NONE); + } + }); + } + } + } else { + showInstallPgpDialog(); + } + } else { + if (encryption != Message.ENCRYPTION_AXOLOTL || !trustKeysIfNeeded(REQUEST_TRUST_KEYS_MENU, attachmentChoice)) { + selectPresenceToAttachFile(attachmentChoice, encryption); + } + } + } + + @Override + public boolean onOptionsItemSelected(final MenuItem item) { + if (item.getItemId() == android.R.id.home) { + showConversationsOverview(); + return true; + } else if (item.getItemId() == R.id.action_add) { + startActivity(new Intent(this, StartConversationActivity.class)); + return true; + } else if (getSelectedConversation() != null) { + switch (item.getItemId()) { + case R.id.action_attach_file: + attachFileDialog(); + break; + case R.id.action_archive: + this.endConversation(getSelectedConversation()); + break; + case R.id.action_contact_details: + switchToContactDetails(getSelectedConversation().getContact()); + break; + case R.id.action_muc_details: + Intent intent = new Intent(this, + ConferenceDetailsActivity.class); + intent.setAction(ConferenceDetailsActivity.ACTION_VIEW_MUC); + intent.putExtra("uuid", getSelectedConversation().getUuid()); + startActivity(intent); + break; + case R.id.action_invite: + inviteToConversation(getSelectedConversation()); + break; + case R.id.action_security: + selectEncryptionDialog(getSelectedConversation()); + break; + case R.id.action_clear_history: + clearHistoryDialog(getSelectedConversation()); + break; + case R.id.action_mute: + muteConversationDialog(getSelectedConversation()); + break; + case R.id.action_unmute: + unmuteConversation(getSelectedConversation()); + break; + case R.id.action_block: + BlockContactDialog.show(this, xmppConnectionService, getSelectedConversation()); + break; + case R.id.action_unblock: + BlockContactDialog.show(this, xmppConnectionService, getSelectedConversation()); + break; + default: + break; + } + return super.onOptionsItemSelected(item); + } else { + return super.onOptionsItemSelected(item); + } + } + + public void endConversation(Conversation conversation) { + endConversation(conversation, true, true); + } + + public void endConversation(Conversation conversation, boolean showOverview, boolean reinit) { + if (showOverview) { + showConversationsOverview(); + } + xmppConnectionService.archiveConversation(conversation); + if (reinit) { + if (conversationList.size() > 0) { + setSelectedConversation(conversationList.get(0)); + this.mConversationFragment.reInit(getSelectedConversation()); + } else { + setSelectedConversation(null); + if (mRedirected.compareAndSet(false, true)) { + Intent intent = new Intent(this, StartConversationActivity.class); + intent.putExtra("init", true); + startActivity(intent); + finish(); + } + } + } + } + + @SuppressLint("InflateParams") + protected void clearHistoryDialog(final Conversation conversation) { + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle(getString(R.string.clear_conversation_history)); + View dialogView = getLayoutInflater().inflate( + R.layout.dialog_clear_history, null); + final CheckBox endConversationCheckBox = (CheckBox) dialogView + .findViewById(R.id.end_conversation_checkbox); + builder.setView(dialogView); + builder.setNegativeButton(getString(R.string.cancel), null); + builder.setPositiveButton(getString(R.string.delete_messages), + new OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int which) { + ConversationActivity.this.xmppConnectionService.clearConversationHistory(conversation); + if (endConversationCheckBox.isChecked()) { + endConversation(conversation); + } else { + updateConversationList(); + ConversationActivity.this.mConversationFragment.updateMessages(); + } + } + }); + builder.create().show(); + } + + protected void attachFileDialog() { + View menuAttachFile = findViewById(R.id.action_attach_file); + if (menuAttachFile == null) { + return; + } + PopupMenu attachFilePopup = new PopupMenu(this, menuAttachFile); + attachFilePopup.inflate(R.menu.attachment_choices); + if (new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION).resolveActivity(getPackageManager()) == null) { + attachFilePopup.getMenu().findItem(R.id.attach_record_voice).setVisible(false); + } + if (new Intent("eu.siacs.conversations.location.request").resolveActivity(getPackageManager()) == null) { + attachFilePopup.getMenu().findItem(R.id.attach_location).setVisible(false); + } + attachFilePopup.setOnMenuItemClickListener(new OnMenuItemClickListener() { + + @Override + public boolean onMenuItemClick(MenuItem item) { + switch (item.getItemId()) { + case R.id.attach_choose_picture: + attachFile(ATTACHMENT_CHOICE_CHOOSE_IMAGE); + break; + case R.id.attach_take_picture: + attachFile(ATTACHMENT_CHOICE_TAKE_PHOTO); + break; + case R.id.attach_choose_file: + attachFile(ATTACHMENT_CHOICE_CHOOSE_FILE); + break; + case R.id.attach_record_voice: + attachFile(ATTACHMENT_CHOICE_RECORD_VOICE); + break; + case R.id.attach_location: + attachFile(ATTACHMENT_CHOICE_LOCATION); + break; + } + return false; + } + }); + attachFilePopup.show(); + } + + public void verifyOtrSessionDialog(final Conversation conversation, View view) { + if (!conversation.hasValidOtrSession() || conversation.getOtrSession().getSessionStatus() != SessionStatus.ENCRYPTED) { + Toast.makeText(this, R.string.otr_session_not_started, Toast.LENGTH_LONG).show(); + return; + } + if (view == null) { + return; + } + PopupMenu popup = new PopupMenu(this, view); + popup.inflate(R.menu.verification_choices); + popup.setOnMenuItemClickListener(new OnMenuItemClickListener() { + @Override + public boolean onMenuItemClick(MenuItem menuItem) { + Intent intent = new Intent(ConversationActivity.this, VerifyOTRActivity.class); + intent.setAction(VerifyOTRActivity.ACTION_VERIFY_CONTACT); + intent.putExtra("contact", conversation.getContact().getJid().toBareJid().toString()); + intent.putExtra("account", conversation.getAccount().getJid().toBareJid().toString()); + switch (menuItem.getItemId()) { + case R.id.scan_fingerprint: + intent.putExtra("mode", VerifyOTRActivity.MODE_SCAN_FINGERPRINT); + break; + case R.id.ask_question: + intent.putExtra("mode", VerifyOTRActivity.MODE_ASK_QUESTION); + break; + case R.id.manual_verification: + intent.putExtra("mode", VerifyOTRActivity.MODE_MANUAL_VERIFICATION); + break; + } + startActivity(intent); + return true; + } + }); + popup.show(); + } + + protected void selectEncryptionDialog(final Conversation conversation) { + View menuItemView = findViewById(R.id.action_security); + if (menuItemView == null) { + return; + } + PopupMenu popup = new PopupMenu(this, menuItemView); + final ConversationFragment fragment = (ConversationFragment) getFragmentManager() + .findFragmentByTag("conversation"); + if (fragment != null) { + popup.setOnMenuItemClickListener(new OnMenuItemClickListener() { + + @Override + public boolean onMenuItemClick(MenuItem item) { + switch (item.getItemId()) { + case R.id.encryption_choice_none: + conversation.setNextEncryption(Message.ENCRYPTION_NONE); + item.setChecked(true); + break; + case R.id.encryption_choice_otr: + conversation.setNextEncryption(Message.ENCRYPTION_OTR); + item.setChecked(true); + break; + case R.id.encryption_choice_pgp: + if (hasPgp()) { + if (conversation.getAccount().getKeys().has("pgp_signature")) { + conversation.setNextEncryption(Message.ENCRYPTION_PGP); + item.setChecked(true); + } else { + announcePgp(conversation.getAccount(), conversation); + } + } else { + showInstallPgpDialog(); + } + break; + case R.id.encryption_choice_axolotl: + Log.d(Config.LOGTAG, AxolotlService.getLogprefix(conversation.getAccount()) + + "Enabled axolotl for Contact " + conversation.getContact().getJid()); + conversation.setNextEncryption(Message.ENCRYPTION_AXOLOTL); + item.setChecked(true); + break; + default: + conversation.setNextEncryption(Message.ENCRYPTION_NONE); + break; + } + xmppConnectionService.databaseBackend.updateConversation(conversation); + fragment.updateChatMsgHint(); + invalidateOptionsMenu(); + refreshUi(); + return true; + } + }); + 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); + MenuItem pgp = popup.getMenu().findItem(R.id.encryption_choice_pgp); + MenuItem axolotl = popup.getMenu().findItem(R.id.encryption_choice_axolotl); + pgp.setVisible(!Config.HIDE_PGP_IN_UI); + if (conversation.getMode() == Conversation.MODE_MULTI) { + otr.setVisible(false); + axolotl.setVisible(false); + } else if (!conversation.getAccount().getAxolotlService().isContactAxolotlCapable(conversation.getContact())) { + axolotl.setEnabled(false); + } + switch (conversation.getNextEncryption()) { + case Message.ENCRYPTION_NONE: + none.setChecked(true); + break; + case Message.ENCRYPTION_OTR: + otr.setChecked(true); + break; + case Message.ENCRYPTION_PGP: + pgp.setChecked(true); + break; + case Message.ENCRYPTION_AXOLOTL: + axolotl.setChecked(true); + break; + default: + none.setChecked(true); + break; + } + popup.show(); + } + } + + protected void muteConversationDialog(final Conversation conversation) { + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle(R.string.disable_notifications); + final int[] durations = getResources().getIntArray(R.array.mute_options_durations); + builder.setItems(R.array.mute_options_descriptions, + new OnClickListener() { + + @Override + public void onClick(final DialogInterface dialog, final int which) { + final long till; + if (durations[which] == -1) { + till = Long.MAX_VALUE; + } else { + till = System.currentTimeMillis() + (durations[which] * 1000); + } + conversation.setMutedTill(till); + ConversationActivity.this.xmppConnectionService.databaseBackend + .updateConversation(conversation); + updateConversationList(); + ConversationActivity.this.mConversationFragment.updateMessages(); + invalidateOptionsMenu(); + } + }); + builder.create().show(); + } + + public void unmuteConversation(final Conversation conversation) { + conversation.setMutedTill(0); + this.xmppConnectionService.databaseBackend.updateConversation(conversation); + updateConversationList(); + ConversationActivity.this.mConversationFragment.updateMessages(); + invalidateOptionsMenu(); + } + + @Override + public void onBackPressed() { + if (!isConversationsOverviewVisable()) { + showConversationsOverview(); + } else { + moveTaskToBack(true); + } + } + + @Override + public boolean onKeyUp(int key, KeyEvent event) { + int rotation = getWindowManager().getDefaultDisplay().getRotation(); + final int upKey; + final int downKey; + switch (rotation) { + case Surface.ROTATION_90: + upKey = KeyEvent.KEYCODE_DPAD_LEFT; + downKey = KeyEvent.KEYCODE_DPAD_RIGHT; + break; + case Surface.ROTATION_180: + upKey = KeyEvent.KEYCODE_DPAD_DOWN; + downKey = KeyEvent.KEYCODE_DPAD_UP; + break; + case Surface.ROTATION_270: + upKey = KeyEvent.KEYCODE_DPAD_RIGHT; + downKey = KeyEvent.KEYCODE_DPAD_LEFT; + break; + default: + upKey = KeyEvent.KEYCODE_DPAD_UP; + downKey = KeyEvent.KEYCODE_DPAD_DOWN; + } + final boolean modifier = event.isCtrlPressed() || event.isAltPressed(); + if (modifier && key == KeyEvent.KEYCODE_TAB && isConversationsOverviewHideable()) { + toggleConversationsOverview(); + return true; + } else if (modifier && key == downKey) { + if (isConversationsOverviewHideable() && !isConversationsOverviewVisable()) { + showConversationsOverview(); + ; + } + return selectDownConversation(); + } else if (modifier && key == upKey) { + if (isConversationsOverviewHideable() && !isConversationsOverviewVisable()) { + showConversationsOverview(); + } + return selectUpConversation(); + } else if (modifier && key == KeyEvent.KEYCODE_1) { + return openConversationByIndex(0); + } else if (modifier && key == KeyEvent.KEYCODE_2) { + return openConversationByIndex(1); + } else if (modifier && key == KeyEvent.KEYCODE_3) { + return openConversationByIndex(2); + } else if (modifier && key == KeyEvent.KEYCODE_4) { + return openConversationByIndex(3); + } else if (modifier && key == KeyEvent.KEYCODE_5) { + return openConversationByIndex(4); + } else if (modifier && key == KeyEvent.KEYCODE_6) { + return openConversationByIndex(5); + } else if (modifier && key == KeyEvent.KEYCODE_7) { + return openConversationByIndex(6); + } else if (modifier && key == KeyEvent.KEYCODE_8) { + return openConversationByIndex(7); + } else if (modifier && key == KeyEvent.KEYCODE_9) { + return openConversationByIndex(8); + } else if (modifier && key == KeyEvent.KEYCODE_0) { + return openConversationByIndex(9); + } else { + return super.onKeyUp(key, event); + } + } + + private void toggleConversationsOverview() { + if (isConversationsOverviewVisable()) { + hideConversationsOverview(); + if (mConversationFragment != null) { + mConversationFragment.setFocusOnInputField(); + } + } else { + showConversationsOverview(); + } + } + + private boolean selectUpConversation() { + if (this.mSelectedConversation != null) { + int index = this.conversationList.indexOf(this.mSelectedConversation); + if (index > 0) { + return openConversationByIndex(index - 1); + } + } + return false; + } + + private boolean selectDownConversation() { + if (this.mSelectedConversation != null) { + int index = this.conversationList.indexOf(this.mSelectedConversation); + if (index != -1 && index < this.conversationList.size() - 1) { + return openConversationByIndex(index + 1); + } + } + return false; + } + + private boolean openConversationByIndex(int index) { + try { + this.conversationWasSelectedByKeyboard = true; + setSelectedConversation(this.conversationList.get(index)); + this.mConversationFragment.reInit(getSelectedConversation()); + if (index > listView.getLastVisiblePosition() - 1 || index < listView.getFirstVisiblePosition() + 1) { + this.listView.setSelection(index); + } + openConversation(); + return true; + } catch (IndexOutOfBoundsException e) { + return false; + } + } + + @Override + protected void onNewIntent(final Intent intent) { + if (xmppConnectionServiceBound) { + if (intent != null && VIEW_CONVERSATION.equals(intent.getType())) { + handleViewConversationIntent(intent); + } + } else { + setIntent(intent); + } + } + + @Override + public void onStart() { + super.onStart(); + this.mRedirected.set(false); + if (this.xmppConnectionServiceBound) { + this.onBackendConnected(); + } + if (conversationList.size() >= 1) { + this.onConversationUpdate(); + } + } + + @Override + public void onPause() { + listView.discardUndo(); + super.onPause(); + this.mActivityPaused = true; + if (this.xmppConnectionServiceBound) { + this.xmppConnectionService.getNotificationService().setIsInForeground(false); + } + } + + @Override + public void onResume() { + super.onResume(); + final int theme = findTheme(); + final boolean usingEnterKey = usingEnterKey(); + if (this.mTheme != theme || usingEnterKey != mUsingEnterKey) { + recreate(); + } + this.mActivityPaused = false; + if (this.xmppConnectionServiceBound) { + this.xmppConnectionService.getNotificationService().setIsInForeground(true); + } + + if (!isConversationsOverviewVisable() || !isConversationsOverviewHideable()) { + sendReadMarkerIfNecessary(getSelectedConversation()); + } + + AppUpdate(); + } + + @Override + public void onSaveInstanceState(final Bundle savedInstanceState) { + Conversation conversation = getSelectedConversation(); + if (conversation != null) { + savedInstanceState.putString(STATE_OPEN_CONVERSATION, + conversation.getUuid()); + } + savedInstanceState.putBoolean(STATE_PANEL_OPEN, + isConversationsOverviewVisable()); + if (this.mPendingImageUris.size() >= 1) { + savedInstanceState.putString(STATE_PENDING_URI, this.mPendingImageUris.get(0).toString()); + } + super.onSaveInstanceState(savedInstanceState); + } + + @Override + void onBackendConnected() { + this.xmppConnectionService.getNotificationService().setIsInForeground(true); + updateConversationList(); + + if (mPendingConferenceInvite != null) { + mPendingConferenceInvite.execute(this); + mPendingConferenceInvite = null; + } + + if (xmppConnectionService.getAccounts().size() == 0) { + if (mRedirected.compareAndSet(false, true)) { + if (Config.X509_VERIFICATION) { + startActivity(new Intent(this, ManageAccountActivity.class)); + } else { + startActivity(new Intent(this, EditAccountActivity.class)); + } + finish(); + } + } else if (conversationList.size() <= 0) { + if (mRedirected.compareAndSet(false, true)) { + Intent intent = new Intent(this, StartConversationActivity.class); + intent.putExtra("init", true); + startActivity(intent); + finish(); + } + } else if (getIntent() != null && VIEW_CONVERSATION.equals(getIntent().getType())) { + handleViewConversationIntent(getIntent()); + } else if (selectConversationByUuid(mOpenConverstaion)) { + if (mPanelOpen) { + showConversationsOverview(); + } else { + if (isConversationsOverviewHideable()) { + openConversation(); + } + } + this.mConversationFragment.reInit(getSelectedConversation()); + mOpenConverstaion = null; + } else if (getSelectedConversation() == null) { + showConversationsOverview(); + mPendingImageUris.clear(); + mPendingFileUris.clear(); + mPendingGeoUri = null; + setSelectedConversation(conversationList.get(0)); + this.mConversationFragment.reInit(getSelectedConversation()); + } else { + this.mConversationFragment.messageListAdapter.updatePreferences(); + this.mConversationFragment.messagesView.invalidateViews(); + this.mConversationFragment.setupIme(); + } + + if (!forbidProcessingPendings) { + for (Iterator<Uri> i = mPendingImageUris.iterator(); i.hasNext(); i.remove()) { + Uri foo = i.next(); + attachImageToConversation(getSelectedConversation(), foo); + } + + for (Iterator<Uri> i = mPendingFileUris.iterator(); i.hasNext(); i.remove()) { + attachFileToConversation(getSelectedConversation(), i.next()); + } + + if (mPendingGeoUri != null) { + attachLocationToConversation(getSelectedConversation(), mPendingGeoUri); + mPendingGeoUri = null; + } + } + forbidProcessingPendings = false; + + ExceptionHelper.checkForCrash(this, this.xmppConnectionService); + setIntent(new Intent()); + } + + private void handleViewConversationIntent(final Intent intent) { + final String uuid = intent.getStringExtra(CONVERSATION); + final String downloadUuid = intent.getStringExtra(MESSAGE); + final String text = intent.getStringExtra(TEXT); + final String nick = intent.getStringExtra(NICK); + final boolean pm = intent.getBooleanExtra(PRIVATE_MESSAGE, false); + if (selectConversationByUuid(uuid)) { + this.mConversationFragment.reInit(getSelectedConversation()); + if (nick != null) { + if (pm) { + Jid jid = getSelectedConversation().getJid(); + try { + Jid next = Jid.fromParts(jid.getLocalpart(), jid.getDomainpart(), nick); + this.mConversationFragment.privateMessageWith(next); + } catch (final InvalidJidException ignored) { + //do nothing + } + } else { + this.mConversationFragment.highlightInConference(nick); + } + } else { + this.mConversationFragment.appendText(text); + } + hideConversationsOverview(); + openConversation(); + if (mContentView instanceof SlidingPaneLayout) { + updateActionBarTitle(true); //fixes bug where slp isn't properly closed yet + } + if (downloadUuid != null) { + final Message message = mSelectedConversation.findMessageWithFileAndUuid(downloadUuid); + if (message != null) { + mConversationFragment.messageListAdapter.startDownloadable(message); + } + } + } + } + + private boolean selectConversationByUuid(String uuid) { + if (uuid == null) { + return false; + } + for (Conversation aConversationList : conversationList) { + if (aConversationList.getUuid().equals(uuid)) { + setSelectedConversation(aConversationList); + return true; + } + } + return false; + } + + @Override + protected void unregisterListeners() { + super.unregisterListeners(); + xmppConnectionService.getNotificationService().setOpenConversation(null); + } + + @SuppressLint("NewApi") + private static List<Uri> extractUriFromIntent(final Intent intent) { + List<Uri> uris = new ArrayList<>(); + Uri uri = intent.getData(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2 && uri == null) { + ClipData clipData = intent.getClipData(); + for (int i = 0; i < clipData.getItemCount(); ++i) { + uris.add(clipData.getItemAt(i).getUri()); + } + } else { + uris.add(uri); + } + return uris; + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, + final Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (resultCode == RESULT_OK) { + if (requestCode == REQUEST_DECRYPT_PGP) { + mConversationFragment.onActivityResult(requestCode, resultCode, data); + } else if (requestCode == ATTACHMENT_CHOICE_CHOOSE_IMAGE) { + mPendingImageUris.clear(); + mPendingImageUris.addAll(extractUriFromIntent(data)); + if (xmppConnectionServiceBound) { + for (Iterator<Uri> i = mPendingImageUris.iterator(); i.hasNext(); i.remove()) { + attachImageToConversation(getSelectedConversation(), i.next()); + } + } + } else if (requestCode == ATTACHMENT_CHOICE_CHOOSE_FILE || requestCode == ATTACHMENT_CHOICE_RECORD_VOICE) { + mPendingFileUris.clear(); + mPendingFileUris.addAll(extractUriFromIntent(data)); + if (xmppConnectionServiceBound) { + for (Iterator<Uri> i = mPendingFileUris.iterator(); i.hasNext(); i.remove()) { + attachFileToConversation(getSelectedConversation(), i.next()); + } + } + } else if (requestCode == ATTACHMENT_CHOICE_TAKE_PHOTO) { + if (mPendingImageUris.size() == 1) { + Uri uri = mPendingImageUris.get(0); + if (xmppConnectionServiceBound) { + attachImageToConversation(getSelectedConversation(), uri); + mPendingImageUris.clear(); + } + Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE); + intent.setData(uri); + sendBroadcast(intent); + } else { + mPendingImageUris.clear(); + } + } else if (requestCode == ATTACHMENT_CHOICE_LOCATION) { + double latitude = data.getDoubleExtra("latitude", 0); + double longitude = data.getDoubleExtra("longitude", 0); + this.mPendingGeoUri = Uri.parse("geo:" + String.valueOf(latitude) + "," + String.valueOf(longitude)); + if (xmppConnectionServiceBound) { + attachLocationToConversation(getSelectedConversation(), mPendingGeoUri); + this.mPendingGeoUri = null; + } + } else if (requestCode == REQUEST_TRUST_KEYS_TEXT || requestCode == REQUEST_TRUST_KEYS_MENU) { + this.forbidProcessingPendings = !xmppConnectionServiceBound; + mConversationFragment.onActivityResult(requestCode, resultCode, data); + } + } else { + mPendingImageUris.clear(); + mPendingFileUris.clear(); + if (requestCode == ConversationActivity.REQUEST_DECRYPT_PGP) { + mConversationFragment.onActivityResult(requestCode, resultCode, data); + } + } + } + + private void attachLocationToConversation(Conversation conversation, Uri uri) { + if (conversation == null) { + return; + } + xmppConnectionService.attachLocationToConversation(conversation, uri, new UiCallback<Message>() { + + @Override + public void success(Message message) { + xmppConnectionService.sendMessage(message); + } + + @Override + public void error(int errorCode, Message object) { + + } + + @Override + public void userInputRequried(PendingIntent pi, Message object) { + + } + }); + } + + private void attachFileToConversation(Conversation conversation, Uri uri) { + if (conversation == null) { + return; + } + prepareFileToast = Toast.makeText(getApplicationContext(), getText(R.string.preparing_file), Toast.LENGTH_LONG); + prepareFileToast.show(); + xmppConnectionService.attachFileToConversation(conversation, uri, new UiCallback<Message>() { + @Override + public void success(Message message) { + hidePrepareFileToast(); + xmppConnectionService.sendMessage(message); + } + + @Override + public void error(int errorCode, Message message) { + displayErrorDialog(errorCode); + } + + @Override + public void userInputRequried(PendingIntent pi, Message message) { + + } + }); + } + + private void attachImageToConversation(Conversation conversation, Uri uri) { + if (conversation == null) { + return; + } + prepareFileToast = Toast.makeText(getApplicationContext(), getText(R.string.preparing_image), Toast.LENGTH_LONG); + prepareFileToast.show(); + xmppConnectionService.attachImageToConversation(conversation, uri, + new UiCallback<Message>() { + + @Override + public void userInputRequried(PendingIntent pi, + Message object) { + hidePrepareFileToast(); + } + + @Override + public void success(Message message) { + xmppConnectionService.sendMessage(message); + } + + @Override + public void error(int error, Message message) { + hidePrepareFileToast(); + displayErrorDialog(error); + } + }); + } + + private void hidePrepareFileToast() { + if (prepareFileToast != null) { + runOnUiThread(new Runnable() { + + @Override + public void run() { + prepareFileToast.cancel(); + } + }); + } + } + + public void updateConversationList() { + xmppConnectionService + .populateWithOrderedConversations(conversationList); + if (swipedConversation != null) { + if (swipedConversation.isRead()) { + conversationList.remove(swipedConversation); + } else { + listView.discardUndo(); + } + } + listAdapter.notifyDataSetChanged(); + } + + public void runIntent(PendingIntent pi, int requestCode) { + try { + this.startIntentSenderForResult(pi.getIntentSender(), requestCode, + null, 0, 0, 0); + } catch (final SendIntentException ignored) { + } + } + + public void encryptTextMessage(Message message) { + xmppConnectionService.getPgpEngine().encrypt(message, + new UiCallback<Message>() { + + @Override + public void userInputRequried(PendingIntent pi, + Message message) { + ConversationActivity.this.runIntent(pi, + ConversationActivity.REQUEST_SEND_MESSAGE); + } + + @Override + public void success(Message message) { + message.setEncryption(Message.ENCRYPTION_DECRYPTED); + xmppConnectionService.sendMessage(message); + } + + @Override + public void error(int error, Message message) { + + } + }); + } + + public boolean useSendButtonToIndicateStatus() { + return getPreferences().getBoolean("send_button_status", false); + } + + public boolean indicateReceived() { + return getPreferences().getBoolean("indicate_received", false); + } + + public boolean useWhiteBackground() { + return getPreferences().getBoolean("use_white_background", false); + } + + protected boolean trustKeysIfNeeded(int requestCode) { + return trustKeysIfNeeded(requestCode, ATTACHMENT_CHOICE_INVALID); + } + + protected boolean trustKeysIfNeeded(int requestCode, int attachmentChoice) { + AxolotlService axolotlService = mSelectedConversation.getAccount().getAxolotlService(); + boolean hasPendingKeys = !axolotlService.getKeysWithTrust(XmppAxolotlSession.Trust.UNDECIDED, + mSelectedConversation.getContact()).isEmpty() + || !axolotlService.findDevicesWithoutSession(mSelectedConversation).isEmpty(); + boolean hasNoTrustedKeys = axolotlService.getNumTrustedKeys(mSelectedConversation.getContact()) == 0; + if (hasPendingKeys || hasNoTrustedKeys) { + axolotlService.createSessionsIfNeeded(mSelectedConversation); + Intent intent = new Intent(getApplicationContext(), TrustKeysActivity.class); + intent.putExtra("contact", mSelectedConversation.getContact().getJid().toBareJid().toString()); + intent.putExtra("account", mSelectedConversation.getAccount().getJid().toBareJid().toString()); + intent.putExtra("choice", attachmentChoice); + intent.putExtra("has_no_trusted", hasNoTrustedKeys); + startActivityForResult(intent, requestCode); + return true; + } else { + return false; + } + } + + @Override + protected void refreshUiReal() { + updateConversationList(); + if (conversationList.size() > 0) { + ConversationActivity.this.mConversationFragment.updateMessages(); + updateActionBarTitle(); + invalidateOptionsMenu(); + } + } + + @Override + public void onAccountUpdate() { + this.refreshUi(); + } + + @Override + public void onConversationUpdate() { + this.refreshUi(); + } + + @Override + public void onRosterUpdate() { + this.refreshUi(); + } + + @Override + public void OnUpdateBlocklist(Status status) { + this.refreshUi(); + } + + public void unblockConversation(final Blockable conversation) { + xmppConnectionService.sendUnblockRequest(conversation); + } + + public boolean enterIsSend() { + return getPreferences().getBoolean("enter_is_send", false); + } + + @Override + public void onShowErrorToast(final int resId) { + runOnUiThread(new Runnable() { + @Override + public void run() { + Toast.makeText(ConversationActivity.this, resId, Toast.LENGTH_SHORT).show(); + } + }); + } + + public boolean highlightSelectedConversations() { + return !isConversationsOverviewHideable() || this.conversationWasSelectedByKeyboard; + } } diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java index 7b83c2bef..fd3426ca7 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java @@ -1011,18 +1011,18 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa if (conversation.getMode() == Conversation.MODE_SINGLE) { ChatState state = conversation.getIncomingChatState(); if (state == ChatState.COMPOSING) { - this.messageList.add(Message.createStatusMessage(conversation, getString(R.string.contact_is_typing, conversation.getName()))); + //this.messageList.add(Message.createStatusMessage(conversation, getString(R.string.contact_is_typing, conversation.getName()))); } else if (state == ChatState.PAUSED) { - this.messageList.add(Message.createStatusMessage(conversation, getString(R.string.contact_has_stopped_typing, conversation.getName()))); + //this.messageList.add(Message.createStatusMessage(conversation, getString(R.string.contact_has_stopped_typing, conversation.getName()))); } else { for (int i = this.messageList.size() - 1; i >= 0; --i) { if (this.messageList.get(i).getStatus() == Message.STATUS_RECEIVED) { return; } else { if (this.messageList.get(i).getStatus() == Message.STATUS_SEND_DISPLAYED) { - this.messageList.add(i + 1, - Message.createStatusMessage(conversation, getString(R.string.contact_has_read_up_to_this_point, conversation.getName()))); - return; +// this.messageList.add(i + 1, +// Message.createStatusMessage(conversation, getString(R.string.contact_has_read_up_to_this_point, conversation.getName()))); +// return; } } } diff --git a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java index 180fc8b84..9ec527d47 100644 --- a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java @@ -29,9 +29,9 @@ import android.widget.RelativeLayout; import android.widget.TableLayout; import android.widget.TextView; import android.widget.Toast; - +import eu.siacs.conversations.Config; +import org.whispersystems.libaxolotl.IdentityKey; import java.util.Set; - import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.crypto.axolotl.AxolotlService; @@ -365,7 +365,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate this.mAxolotlFingerprint = (TextView) findViewById(R.id.axolotl_fingerprint); this.mAxolotlFingerprintBox = (RelativeLayout) findViewById(R.id.axolotl_fingerprint_box); this.mAxolotlFingerprintToClipboardButton = (ImageButton) findViewById(R.id.action_copy_axolotl_to_clipboard); - this.mRegenerateAxolotlKeyButton = (ImageButton) findViewById(R.id.action_regenerate_axolotl_key); + this.mRegenerateAxolotlKeyButton = (ImageButton) findViewById(R.id.action_regenerate_omemo_key); this.keysCard = (LinearLayout) findViewById(R.id.other_device_keys_card); this.keys = (LinearLayout) findViewById(R.id.other_device_keys); this.mSaveButton = (Button) findViewById(R.id.save_button); @@ -538,7 +538,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate } if (!mInitMode) { this.mAvatar.setVisibility(View.VISIBLE); - this.mAvatar.setImageBitmap(avatarService().get(this.mAccount, getPixel(72))); + this.mAvatar.setImageBitmap(avatarService().get(this.mAccount, getPixel(Config.AVATAR_SIZE))); } if (this.mAccount.isOptionSet(Account.OPTION_REGISTER)) { this.mRegisterNew.setVisibility(View.VISIBLE); diff --git a/src/main/java/eu/siacs/conversations/ui/PublishProfilePictureActivity.java b/src/main/java/eu/siacs/conversations/ui/PublishProfilePictureActivity.java index e01490f90..9e64a6805 100644 --- a/src/main/java/eu/siacs/conversations/ui/PublishProfilePictureActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/PublishProfilePictureActivity.java @@ -172,7 +172,7 @@ public class PublishProfilePictureActivity extends XmppActivity { if (this.account.getAvatar() != null || this.defaultUri == null) { this.avatar.setImageBitmap(avatarService().get(account, - getPixel(194))); + getPixel(Config.AVATAR_SIZE))); if (this.defaultUri != null) { this.avatar .setOnLongClickListener(this.backToDefaultListener); @@ -219,7 +219,7 @@ public class PublishProfilePictureActivity extends XmppActivity { protected void loadImageIntoPreview(Uri uri) { Bitmap bm = xmppConnectionService.getFileBackend().cropCenterSquare( - uri, 384); + uri, Config.AVATAR_SIZE); if (bm == null) { disablePublishButton(); this.hintOrWarning.setTextColor(getWarningTextColor()); diff --git a/src/main/java/eu/siacs/conversations/ui/UpdaterActivity.java b/src/main/java/eu/siacs/conversations/ui/UpdaterActivity.java new file mode 100644 index 000000000..4dccdfe5b --- /dev/null +++ b/src/main/java/eu/siacs/conversations/ui/UpdaterActivity.java @@ -0,0 +1,262 @@ +package eu.siacs.conversations.ui; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.DownloadManager; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.net.Uri; +import android.os.Bundle; +import android.os.Environment; +import android.util.Log; +import android.view.WindowManager; +import android.widget.TextView; +import android.widget.Toast; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.File; + +import eu.siacs.conversations.Config; +import eu.siacs.conversations.R; +import eu.siacs.conversations.services.UpdaterWebService; + +public class UpdaterActivity extends Activity { + + private UpdateReceiver receiver = null; + private int versionCode = 0; + String appURI = ""; + + + /* + // run AppUpdater + Log.d(Config.LOGTAG, "Start automatic AppUpdater"); + Intent AppUpdater = new Intent(this, UpdaterActivity.class); + startActivity(AppUpdater); + */ + + private DownloadManager downloadManager; + private long downloadReference; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + //set activity + setContentView(R.layout.activity_updater); + TextView textView = (TextView) findViewById(R.id.updater); + textView.setText(R.string.update_info); + + //Broadcast receiver for our Web Request + IntentFilter filter = new IntentFilter(UpdateReceiver.PROCESS_RESPONSE); + filter.addCategory(Intent.CATEGORY_DEFAULT); + receiver = new UpdateReceiver(); + registerReceiver(receiver, filter); + + //Broadcast receiver for the download manager + filter = new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE); + registerReceiver(downloadReceiver, filter); + + //check of internet is available before making a web service request + if (isNetworkAvailable(this)) { + Intent msgIntent = new Intent(this, UpdaterWebService.class); + msgIntent.putExtra(UpdaterWebService.REQUEST_STRING, Config.UPDATE_URL); + + Toast.makeText(getApplicationContext(), + getText(R.string.checking_for_updates), + Toast.LENGTH_SHORT).show(); + startService(msgIntent); + } + } + + @Override + public void onDestroy() { + //unregister your receivers + this.unregisterReceiver(receiver); + this.unregisterReceiver(downloadReceiver); + super.onDestroy(); + //enable touch events + getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE); + } + + @Override + public void onSaveInstanceState(Bundle savedInstanceState) { + super.onSaveInstanceState(savedInstanceState); + } + + @Override + public void onRestoreInstanceState(Bundle savedInstanceState) { + super.onRestoreInstanceState(savedInstanceState); + } + + //check for internet connection + private boolean isNetworkAvailable(Context context) { + ConnectivityManager connectivity = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + if (connectivity != null) { + NetworkInfo[] info = connectivity.getAllNetworkInfo(); + if (info != null) { + for (int i = 0; i < info.length; i++) { + Log.d(Config.LOGTAG, "AppUpdater: " + String.valueOf(i)); + if (info[i].getState() == NetworkInfo.State.CONNECTED) { + Log.d(Config.LOGTAG, "AppUpdater: connected to update Server!"); + return true; + } + } + } + } + return false; + } + + //broadcast receiver to get notification when the web request finishes + public class UpdateReceiver extends BroadcastReceiver { + + public static final String PROCESS_RESPONSE = "eu.siacs.conversations.intent.action.PROCESS_RESPONSE"; + + @Override + public void onReceive(Context context, Intent intent) { + //disable touch events + getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, + WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE); + + String reponseMessage = intent.getStringExtra(UpdaterWebService.RESPONSE_MESSAGE); + Log.d(Config.LOGTAG, "AppUpdater: Reponse: " + reponseMessage); + + if (reponseMessage == "" || reponseMessage.isEmpty() || reponseMessage == null) { + Toast.makeText(getApplicationContext(), + getText(R.string.failed), + Toast.LENGTH_LONG).show(); + Log.e(Config.LOGTAG, "AppUpdater: error connecting to server"); + UpdaterActivity.this.finish(); + } else { + Log.d(Config.LOGTAG, "AppUpdater: connecting to server"); + //parse the JSON reponse + JSONObject reponseObj; + + try { + //if the reponse was successful check further + reponseObj = new JSONObject(reponseMessage); + boolean success = reponseObj.getBoolean("success"); + if (success) { + //Overall information about the contents of a package + //This correponds to all of the information collected from AndroidManifest.xml. + PackageInfo pInfo = null; + try { + pInfo = getPackageManager().getPackageInfo(getPackageName(), 0); + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + } + //get the app version Name for display + final String versionName = pInfo.versionName; + final int versionCode = pInfo.versionCode; + //get the latest version from the JSON string + int latestVersionCode = reponseObj.getInt("latestVersionCode"); + String latestVersion = reponseObj.getString("latestVersion"); + String changelog = reponseObj.getString("changelog"); + //get the lastest application URI from the JSON string + appURI = reponseObj.getString("appURI"); + //check if we need to upgrade? + if (latestVersionCode > versionCode) { + Log.d(Config.LOGTAG, "AppUpdater: update available"); + //delete old downloaded version files + File dir = new File(getExternalFilesDir(null), Environment.DIRECTORY_DOWNLOADS); + Log.d(Config.LOGTAG, "AppUpdater: delete old update files in: " + dir); + if (dir.isDirectory()) { + String[] children = dir.list(); + for (int i = 0; i < children.length; i++) { + new File(dir, children[i]).delete(); + } + } + //enable touch events + getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE); + + //oh yeah we do need an upgrade, let the user know send an alert message + AlertDialog.Builder builder = new AlertDialog.Builder(UpdaterActivity.this); + builder.setCancelable(false); + + String UpdateMessageInfo = getResources().getString(R.string.update_available); + builder.setMessage(String.format(UpdateMessageInfo, latestVersion, changelog, versionName)) + .setPositiveButton(R.string.update, new DialogInterface.OnClickListener() { + //if the user agrees to upgrade + public void onClick(DialogInterface dialog, int id) { + //disable touch events + getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, + WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE); + //start downloading the file using the download manager + downloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE); + Uri Download_Uri = Uri.parse(appURI); + DownloadManager.Request request = new DownloadManager.Request(Download_Uri); + request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI); + request.setAllowedOverRoaming(false); + request.setTitle("Conversations Update"); + request.setDestinationInExternalFilesDir(UpdaterActivity.this, Environment.DIRECTORY_DOWNLOADS, "Conversations" + versionName + ".apk"); + downloadReference = downloadManager.enqueue(request); + Toast.makeText(getApplicationContext(), + getText(R.string.download_started), + Toast.LENGTH_LONG).show(); + } + }) + .setNegativeButton(R.string.remind_later, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + // User cancelled the dialog + UpdaterActivity.this.finish(); + } + }); + //show the alert message + builder.create().show(); + } else { + Toast.makeText(getApplicationContext(), + getText(R.string.no_update_available), + Toast.LENGTH_SHORT).show(); + Log.d(Config.LOGTAG, "AppUpdater: no update available"); + UpdaterActivity.this.finish(); + } + } else { + Toast.makeText(getApplicationContext(), + getText(R.string.failed), + Toast.LENGTH_LONG).show(); + Log.e(Config.LOGTAG, "AppUpdater: contact to server not successfull"); + UpdaterActivity.this.finish(); + } + } catch (JSONException e) { + e.printStackTrace(); + } + } + + } + + } + + //broadcast receiver to get notification about ongoing downloads + private BroadcastReceiver downloadReceiver = new BroadcastReceiver() { + + @Override + public void onReceive(Context context, Intent intent) { + //check if the broadcast message is for our Enqueued download + long referenceId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1); + if (downloadReference == referenceId) { + + Log.d(Config.LOGTAG, "AppUpdater: Downloading of the new app version complete. Starting installation"); + //start the installation of the latest version + Intent installIntent = new Intent(Intent.ACTION_VIEW); + installIntent.setDataAndType(downloadManager.getUriForDownloadedFile(downloadReference), + "application/vnd.android.package-archive"); + installIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + startActivity(installIntent); + UpdaterActivity.this.finish(); + } + } + }; + + //disable back button + @Override + public void onBackPressed() { + } +} diff --git a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java index aa03a61df..9dae18157 100644 --- a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java @@ -334,6 +334,9 @@ public abstract class XmppActivity extends Activity { case R.id.action_settings: startActivity(new Intent(this, SettingsActivity.class)); break; + case R.id.action_check_updates: + startActivity(new Intent(this, UpdaterActivity.class)); + break; case R.id.action_accounts: startActivity(new Intent(this, ManageAccountActivity.class)); break; diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/AccountAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/AccountAdapter.java index 98250af94..c1b9cbdf6 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/AccountAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/AccountAdapter.java @@ -43,7 +43,7 @@ public class AccountAdapter extends ArrayAdapter<Account> { } TextView statusView = (TextView) view.findViewById(R.id.account_status); ImageView imageView = (ImageView) view.findViewById(R.id.account_image); - imageView.setImageBitmap(activity.avatarService().get(account, activity.getPixel(48))); + imageView.setImageBitmap(activity.avatarService().get(account, activity.getPixel(56))); statusView.setText(getContext().getString(account.getStatus().getReadableId())); switch (account.getStatus()) { case ONLINE: diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java index 019b83d35..039efe3c5 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java @@ -121,6 +121,7 @@ public class MessageAdapter extends ArrayAdapter<Message> { boolean error = false; if (viewHolder.indicatorReceived != null) { viewHolder.indicatorReceived.setVisibility(View.GONE); + viewHolder.indicatorRead.setVisibility(View.GONE); } boolean multiReceived = message.getConversation().getMode() == Conversation.MODE_MULTI && message.getMergedStatus() <= Message.STATUS_RECEIVED; @@ -158,6 +159,7 @@ public class MessageAdapter extends ArrayAdapter<Message> { case Message.STATUS_SEND_DISPLAYED: if (mIndicateReceived) { viewHolder.indicatorReceived.setVisibility(View.VISIBLE); + viewHolder.indicatorRead.setVisibility(View.VISIBLE); } break; case Message.STATUS_SEND_FAILED: @@ -396,7 +398,7 @@ public class MessageAdapter extends ArrayAdapter<Message> { viewHolder.messageBody.setVisibility(View.GONE); viewHolder.image.setVisibility(View.VISIBLE); FileParams params = message.getFileParams(); - double target = metrics.density * 288; + double target = metrics.density * 200; int scalledW; int scalledH; if (params.width <= params.height) { @@ -450,6 +452,8 @@ public class MessageAdapter extends ArrayAdapter<Message> { .findViewById(R.id.message_time); viewHolder.indicatorReceived = (ImageView) view .findViewById(R.id.indicator_received); + viewHolder.indicatorRead = (ImageView) view + .findViewById(R.id.indicator_read); break; case RECEIVED: view = activity.getLayoutInflater().inflate( @@ -670,6 +674,7 @@ public class MessageAdapter extends ArrayAdapter<Message> { protected ImageView image; protected ImageView indicator; protected ImageView indicatorReceived; + protected ImageView indicatorRead; protected TextView time; protected TextView messageBody; protected ImageView contact_picture; diff --git a/src/main/java/eu/siacs/conversations/utils/ExceptionHelper.java b/src/main/java/eu/siacs/conversations/utils/ExceptionHelper.java index 0f1828473..6d1d1074d 100644 --- a/src/main/java/eu/siacs/conversations/utils/ExceptionHelper.java +++ b/src/main/java/eu/siacs/conversations/utils/ExceptionHelper.java @@ -94,7 +94,7 @@ public class ExceptionHelper { Conversation conversation = null; try { conversation = service.findOrCreateConversation(finalAccount, - Jid.fromString("bugs@siacs.eu"), false); + Jid.fromString("bugs@pix-art.de"), false); } catch (final InvalidJidException ignored) { } Message message = new Message(conversation, report diff --git a/src/main/java/eu/siacs/conversations/utils/GeoHelper.java b/src/main/java/eu/siacs/conversations/utils/GeoHelper.java index 74f91a98b..cd97e1105 100644 --- a/src/main/java/eu/siacs/conversations/utils/GeoHelper.java +++ b/src/main/java/eu/siacs/conversations/utils/GeoHelper.java @@ -9,6 +9,7 @@ import java.util.ArrayList; import java.util.regex.Matcher; import java.util.regex.Pattern; +import eu.siacs.conversations.entities.Contact; import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.entities.Message; @@ -40,6 +41,7 @@ public class GeoHelper { return intents; } final Conversation conversation = message.getConversation(); + final Contact contact = message.getContact(); String label; if (conversation.getMode() == Conversation.MODE_SINGLE && message.getStatus() == Message.STATUS_RECEIVED) { try { @@ -62,6 +64,16 @@ public class GeoHelper { else { locationPluginIntent.putExtra("jid",conversation.getAccount().getJid().toString()); } + } else { + if (message.getStatus() == Message.STATUS_RECEIVED) { + if (contact != null) { + locationPluginIntent.putExtra("name",contact.getDisplayName()); + } + locationPluginIntent.putExtra("jid",message.getCounterpart().toString()); + } + else { + locationPluginIntent.putExtra("jid",conversation.getAccount().getJid().toString()); + } } intents.add(locationPluginIntent); @@ -74,4 +86,4 @@ public class GeoHelper { intents.add(httpIntent); return intents; } -} +}
\ No newline at end of file diff --git a/src/main/java/eu/siacs/conversations/xmpp/OnNewKeysAvailable.java b/src/main/java/eu/siacs/conversations/xmpp/OnNewKeysAvailable.java new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/main/java/eu/siacs/conversations/xmpp/OnNewKeysAvailable.java |