diff options
Diffstat (limited to 'src/main/java')
65 files changed, 2346 insertions, 633 deletions
diff --git a/src/main/java/eu/siacs/conversations/Config.java b/src/main/java/eu/siacs/conversations/Config.java index ee2f3f195..68ad2c122 100644 --- a/src/main/java/eu/siacs/conversations/Config.java +++ b/src/main/java/eu/siacs/conversations/Config.java @@ -6,7 +6,6 @@ import eu.siacs.conversations.xmpp.chatstate.ChatState; public final class Config { - private static final int UNENCRYPTED = 1; private static final int OPENPGP = 2; private static final int OTR = 4; @@ -34,20 +33,30 @@ public final class Config { return (ENCRYPTION_MASK & (ENCRYPTION_MASK - 1)) != 0; } - public static final String LOGTAG = "conversations"; + public static boolean AlwayUseOMEMO = false; //true makes OMEMO as default on every 1 to 1 chat + + public static final String LOGTAG = "Pix-Art Messenger"; - public static final String BUG_REPORTS = "bugs@conversations.im"; + public static final String XMPP_IP = "185.26.156.37"; // set to null means disable + public static final Integer[] XMPP_Ports = {61000, 65000}; // set to null means disable + public static final String BUG_REPORTS = "bugs@pix-art.de"; - public static final String DOMAIN_LOCK = null; //only allow account creation for this domain - public static final String MAGIC_CREATE_DOMAIN = "conversations.im"; + public static String inviteUserURL = "https://jabber.pix-art.de/i/"; + + public static final String DOMAIN_LOCK = "pix-art.de"; //only allow account creation for this domain + public static final String MAGIC_CREATE_DOMAIN = "pix-art.de"; + public static final boolean SINGLE_ACCOUNT = true; //set to true to allow only one account public static final boolean DISALLOW_REGISTRATION_IN_UI = false; //hide the register checkbox public static final boolean ALLOW_NON_TLS_CONNECTIONS = false; //very dangerous. you should have a good reason to set this to true + public static final boolean FORCE_ORBOT = false; // always use TOR public static final boolean HIDE_MESSAGE_TEXT_IN_NOTIFICATION = false; + public static final boolean SHOW_CONNECTED_ACCOUNTS = false; //show number of connected accounts in foreground notification - public static final boolean SHOW_DISABLE_FOREGROUND = true; //if set to true the foreground notification has a button to disable it + public static final boolean SHOW_DISABLE_FOREGROUND = false; //if set to true the foreground notification has a button to disable it + public static final boolean USE_ALWAYS_FOREGROUND = true; //if set to true the foreground service is always enabled public static final boolean ALWAYS_NOTIFY_BY_DEFAULT = false; @@ -56,19 +65,24 @@ public final class Config { public static final int PING_MIN_INTERVAL = 30; public static final int PING_TIMEOUT = 15; public static final int SOCKET_TIMEOUT = 15; - public static final int CONNECT_TIMEOUT = 90; - public static final int CONNECT_DISCO_TIMEOUT = 20; + public static final int CONNECT_TIMEOUT = 60; + public static final int CONNECT_DISCO_TIMEOUT = 30; + public static final int CARBON_GRACE_PERIOD = 90; public static final int MINI_GRACE_PERIOD = 750; public static final boolean CLOSE_TCP_WHEN_SWITCHING_TO_BACKGROUND = false; - public static final int AVATAR_SIZE = 192; - public static final Bitmap.CompressFormat AVATAR_FORMAT = Bitmap.CompressFormat.WEBP; + public static final int AVATAR_SIZE = 720; + public static final Bitmap.CompressFormat AVATAR_FORMAT = Bitmap.CompressFormat.JPEG; public static final int IMAGE_SIZE = 1920; public static final Bitmap.CompressFormat IMAGE_FORMAT = Bitmap.CompressFormat.JPEG; public static final int IMAGE_QUALITY = 75; - public static final int IMAGE_MAX_SIZE = 524288; //512KiB + public static final int IMAGE_MAX_SIZE = 524288; //512 KiB + + public static final int FILE_MAX_SIZE = 1048576; //1 MiB + + public static final int DEFAULT_ZOOM = 15; //for locations public static final int MESSAGE_MERGE_WINDOW = 20; @@ -101,7 +115,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/Pix-Art_Messenger/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/crypto/PgpDecryptionService.java b/src/main/java/eu/siacs/conversations/crypto/PgpDecryptionService.java index ed67dc65f..5afbe5c49 100644 --- a/src/main/java/eu/siacs/conversations/crypto/PgpDecryptionService.java +++ b/src/main/java/eu/siacs/conversations/crypto/PgpDecryptionService.java @@ -2,15 +2,15 @@ package eu.siacs.conversations.crypto; import android.app.PendingIntent; -import eu.siacs.conversations.entities.Message; -import eu.siacs.conversations.services.XmppConnectionService; -import eu.siacs.conversations.ui.UiCallback; - import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.concurrent.ConcurrentHashMap; +import eu.siacs.conversations.entities.Message; +import eu.siacs.conversations.services.XmppConnectionService; +import eu.siacs.conversations.ui.UiCallback; + public class PgpDecryptionService { private final XmppConnectionService xmppConnectionService; diff --git a/src/main/java/eu/siacs/conversations/crypto/sasl/External.java b/src/main/java/eu/siacs/conversations/crypto/sasl/External.java index df92898c1..8fd91cf47 100644 --- a/src/main/java/eu/siacs/conversations/crypto/sasl/External.java +++ b/src/main/java/eu/siacs/conversations/crypto/sasl/External.java @@ -1,6 +1,7 @@ package eu.siacs.conversations.crypto.sasl; import android.util.Base64; + import java.security.SecureRandom; import eu.siacs.conversations.entities.Account; diff --git a/src/main/java/eu/siacs/conversations/entities/Account.java b/src/main/java/eu/siacs/conversations/entities/Account.java index 3e79fccd9..dec3bd1a4 100644 --- a/src/main/java/eu/siacs/conversations/entities/Account.java +++ b/src/main/java/eu/siacs/conversations/entities/Account.java @@ -5,7 +5,6 @@ import android.database.Cursor; import android.os.SystemClock; import android.util.Pair; -import eu.siacs.conversations.crypto.PgpDecryptionService; import net.java.otr4j.crypto.OtrCryptoEngineImpl; import net.java.otr4j.crypto.OtrCryptoException; @@ -23,6 +22,7 @@ import java.util.concurrent.CopyOnWriteArraySet; import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.crypto.OtrService; +import eu.siacs.conversations.crypto.PgpDecryptionService; import eu.siacs.conversations.crypto.axolotl.AxolotlService; import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.xmpp.XmppConnection; diff --git a/src/main/java/eu/siacs/conversations/entities/Bookmark.java b/src/main/java/eu/siacs/conversations/entities/Bookmark.java index c5c4ff5dd..7c2f73b36 100644 --- a/src/main/java/eu/siacs/conversations/entities/Bookmark.java +++ b/src/main/java/eu/siacs/conversations/entities/Bookmark.java @@ -6,7 +6,6 @@ import java.util.ArrayList; import java.util.List; import java.util.Locale; -import eu.siacs.conversations.Config; import eu.siacs.conversations.utils.UIHelper; import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xmpp.jid.Jid; diff --git a/src/main/java/eu/siacs/conversations/entities/Conversation.java b/src/main/java/eu/siacs/conversations/entities/Conversation.java index 017a85f51..c194ad7d2 100644 --- a/src/main/java/eu/siacs/conversations/entities/Conversation.java +++ b/src/main/java/eu/siacs/conversations/entities/Conversation.java @@ -447,6 +447,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; @@ -682,7 +695,8 @@ public class Conversation extends AbstractEntity implements Blockable { && mode == MODE_SINGLE && axolotlService.isConversationAxolotlCapable(this) && getAccount().getSelfContact().getPresences().allOrNonSupport(AxolotlService.PEP_DEVICE_LIST_NOTIFY) - && getContact().getPresences().allOrNonSupport(AxolotlService.PEP_DEVICE_LIST_NOTIFY)) { + && getContact().getPresences().allOrNonSupport(AxolotlService.PEP_DEVICE_LIST_NOTIFY) + && Config.AlwayUseOMEMO){ return Message.ENCRYPTION_AXOLOTL; } else { next = this.getMostRecentlyUsedIncomingEncryption(); diff --git a/src/main/java/eu/siacs/conversations/entities/Message.java b/src/main/java/eu/siacs/conversations/entities/Message.java index 21837386d..3c871dc79 100644 --- a/src/main/java/eu/siacs/conversations/entities/Message.java +++ b/src/main/java/eu/siacs/conversations/entities/Message.java @@ -5,7 +5,6 @@ import android.database.Cursor; import java.net.MalformedURLException; import java.net.URL; -import java.util.Arrays; import eu.siacs.conversations.Config; import eu.siacs.conversations.crypto.axolotl.XmppAxolotlSession; diff --git a/src/main/java/eu/siacs/conversations/entities/MucOptions.java b/src/main/java/eu/siacs/conversations/entities/MucOptions.java index d08483703..043bc03d0 100644 --- a/src/main/java/eu/siacs/conversations/entities/MucOptions.java +++ b/src/main/java/eu/siacs/conversations/entities/MucOptions.java @@ -3,7 +3,6 @@ package eu.siacs.conversations.entities; import android.annotation.SuppressLint; import java.util.ArrayList; -import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -554,7 +553,7 @@ public class MucOptions { } public String createNameFromParticipants() { - if (getUserCount() >= 2) { + if (users.size() >= 1) { List<String> names = new ArrayList<>(); for (User user : getUsers(5)) { Contact contact = user.getContact(); diff --git a/src/main/java/eu/siacs/conversations/entities/Presence.java b/src/main/java/eu/siacs/conversations/entities/Presence.java index e9f6d0d16..eefe73fc0 100644 --- a/src/main/java/eu/siacs/conversations/entities/Presence.java +++ b/src/main/java/eu/siacs/conversations/entities/Presence.java @@ -1,6 +1,5 @@ package eu.siacs.conversations.entities; -import java.lang.Comparable; import java.util.Locale; import eu.siacs.conversations.xml.Element; diff --git a/src/main/java/eu/siacs/conversations/entities/Presences.java b/src/main/java/eu/siacs/conversations/entities/Presences.java index 9e94ff2b3..b3e8966a7 100644 --- a/src/main/java/eu/siacs/conversations/entities/Presences.java +++ b/src/main/java/eu/siacs/conversations/entities/Presences.java @@ -3,11 +3,7 @@ package eu.siacs.conversations.entities; import java.util.ArrayList; import java.util.Collections; import java.util.Hashtable; -import java.util.Iterator; import java.util.List; -import java.util.Map; - -import eu.siacs.conversations.xml.Element; public class Presences { private final Hashtable<String, Presence> presences = new Hashtable<>(); diff --git a/src/main/java/eu/siacs/conversations/entities/ServiceDiscoveryResult.java b/src/main/java/eu/siacs/conversations/entities/ServiceDiscoveryResult.java index 9ee1d180e..4de7c7e7a 100644 --- a/src/main/java/eu/siacs/conversations/entities/ServiceDiscoveryResult.java +++ b/src/main/java/eu/siacs/conversations/entities/ServiceDiscoveryResult.java @@ -3,17 +3,18 @@ package eu.siacs.conversations.entities; import android.content.ContentValues; import android.database.Cursor; import android.util.Base64; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + import java.io.UnsupportedEncodingException; -import java.lang.Comparable; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xmpp.forms.Data; diff --git a/src/main/java/eu/siacs/conversations/entities/Transferable.java b/src/main/java/eu/siacs/conversations/entities/Transferable.java index 5a47c4512..1ce4d8ccf 100644 --- a/src/main/java/eu/siacs/conversations/entities/Transferable.java +++ b/src/main/java/eu/siacs/conversations/entities/Transferable.java @@ -4,28 +4,75 @@ import java.util.Arrays; import java.util.List; public interface Transferable { + List<String> VALID_IMAGE_EXTENSIONS = Arrays.asList( + "webp", + "jpeg", + "jpg", + "png", + "jpe", + "gif", + "tif" + ); + List<String> VALID_CRYPTO_EXTENSIONS = Arrays.asList( + "pgp", + "gpg", + "otr" + ); + List<String> WELL_KNOWN_EXTENSIONS = Arrays.asList( + //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" + ); - List<String> VALID_IMAGE_EXTENSIONS = Arrays.asList("webp", "jpeg", "jpg", "png", "jpe"); - List<String> VALID_CRYPTO_EXTENSIONS = Arrays.asList("pgp", "gpg", "otr"); - List<String> WELL_KNOWN_EXTENSIONS = Arrays.asList("pdf","m4a","mp4","3gp","aac","amr","mp3"); + int STATUS_UNKNOWN = 0x200; + int STATUS_CHECKING = 0x201; + int STATUS_FAILED = 0x202; + int STATUS_OFFER = 0x203; + int STATUS_DOWNLOADING = 0x204; + int STATUS_DELETED = 0x205; + int STATUS_OFFER_CHECK_FILESIZE = 0x206; + int STATUS_UPLOADING = 0x207; - int STATUS_UNKNOWN = 0x200; - int STATUS_CHECKING = 0x201; - int STATUS_FAILED = 0x202; - int STATUS_OFFER = 0x203; - int STATUS_DOWNLOADING = 0x204; - int STATUS_DELETED = 0x205; - int STATUS_OFFER_CHECK_FILESIZE = 0x206; - int STATUS_UPLOADING = 0x207; + boolean start(); - boolean start(); + int getStatus(); - int getStatus(); + long getFileSize(); - long getFileSize(); + int getProgress(); - int getProgress(); - - void cancel(); + void cancel(); } diff --git a/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java b/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java index 9e8396835..64bd5e50e 100644 --- a/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java +++ b/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java @@ -16,8 +16,6 @@ import eu.siacs.conversations.Config; import eu.siacs.conversations.crypto.axolotl.AxolotlService; import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.utils.PhoneHelper; -import eu.siacs.conversations.xmpp.jid.Jid; -import eu.siacs.conversations.xmpp.stanzas.IqPacket; public abstract class AbstractGenerator { private final String[] FEATURES = { @@ -42,7 +40,9 @@ public abstract class AbstractGenerator { "urn:xmpp:message-correct:0" }; private String mVersion = null; - protected final String IDENTITY_NAME = "Conversations"; + + private String mVersionOs = null; + protected final String IDENTITY_NAME = "Pix-Art Messenger"; protected final String IDENTITY_TYPE = "phone"; private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US); @@ -60,6 +60,14 @@ public abstract class AbstractGenerator { return this.mVersion; } + protected String getIdentityVersionOs() { + if (mVersionOs == null) { + this.mVersionOs = "Android/" + android.os.Build.MODEL + + "/" + android.os.Build.VERSION.RELEASE; + } + return this.mVersionOs; + } + public String getIdentityName() { return IDENTITY_NAME + " " + getIdentityVersion(); } diff --git a/src/main/java/eu/siacs/conversations/generator/IqGenerator.java b/src/main/java/eu/siacs/conversations/generator/IqGenerator.java index 2e441727c..16af338c6 100644 --- a/src/main/java/eu/siacs/conversations/generator/IqGenerator.java +++ b/src/main/java/eu/siacs/conversations/generator/IqGenerator.java @@ -58,6 +58,7 @@ public class IqGenerator extends AbstractGenerator { Element query = packet.query("jabber:iq:version"); query.addChild("name").setContent(IDENTITY_NAME); query.addChild("version").setContent(getIdentityVersion()); + query.addChild("os").setContent(getIdentityVersionOs()); return packet; } diff --git a/src/main/java/eu/siacs/conversations/http/HttpConnectionManager.java b/src/main/java/eu/siacs/conversations/http/HttpConnectionManager.java index a8b31a7a9..f105646f0 100644 --- a/src/main/java/eu/siacs/conversations/http/HttpConnectionManager.java +++ b/src/main/java/eu/siacs/conversations/http/HttpConnectionManager.java @@ -1,7 +1,5 @@ package eu.siacs.conversations.http; -import android.os.Build; - import org.apache.http.conn.ssl.StrictHostnameVerifier; import java.io.IOException; diff --git a/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java b/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java index d23cb71a3..c7d68de16 100644 --- a/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java +++ b/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java @@ -10,6 +10,9 @@ import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; import java.util.concurrent.CancellationException; import javax.net.ssl.HttpsURLConnection; @@ -40,6 +43,8 @@ public class HttpDownloadConnection implements Transferable { private boolean mUseTor = false; private boolean canceled = false; + private final SimpleDateFormat fileDateFormat = new SimpleDateFormat("yyyyMMdd_HHmmssSSS", Locale.US); + public HttpDownloadConnection(HttpConnectionManager manager) { this.mHttpConnectionManager = manager; this.mXmppConnectionService = manager.getXmppConnectionService(); @@ -88,7 +93,8 @@ public class HttpDownloadConnection implements Transferable { } else { extension = lastPart; } - message.setRelativeFilePath(message.getUuid() + "." + extension); + String filename = fileDateFormat.format(new Date(message.getTimeSent())); + message.setRelativeFilePath(filename + "." + extension); this.file = mXmppConnectionService.getFileBackend().getFile(message, false); String reference = mUrl.getRef(); if (reference != null && reference.length() == 96) { @@ -189,7 +195,9 @@ public class HttpDownloadConnection implements Transferable { } private long retrieveFileSize() throws IOException { + PowerManager.WakeLock wakeLock = mHttpConnectionManager.createWakeLock("http_download_"+message.getUuid()); try { + wakeLock.acquire(); Log.d(Config.LOGTAG, "retrieve file size. interactive:" + String.valueOf(interactive)); changeStatus(STATUS_CHECKING); HttpURLConnection connection; @@ -211,6 +219,7 @@ public class HttpDownloadConnection implements Transferable { if (contentLength == null) { throw new IOException(); } + wakeLock.release(); return Long.parseLong(contentLength, 10); } catch (IOException e) { throw e; diff --git a/src/main/java/eu/siacs/conversations/http/HttpUploadConnection.java b/src/main/java/eu/siacs/conversations/http/HttpUploadConnection.java index 87c6fc4aa..56f1ed5bf 100644 --- a/src/main/java/eu/siacs/conversations/http/HttpUploadConnection.java +++ b/src/main/java/eu/siacs/conversations/http/HttpUploadConnection.java @@ -89,8 +89,12 @@ public class HttpUploadConnection implements Transferable { private void fail() { mHttpConnectionManager.finishUploadConnection(this); message.setTransferable(null); - mXmppConnectionService.markMessage(message, Message.STATUS_SEND_FAILED); - FileBackend.close(mFileInputStream); + if (!canceled && file.getExpectedSize()<=Config.FILE_MAX_SIZE){ + mXmppConnectionService.resendMessage(message, delayed); + } else { + mXmppConnectionService.markMessage(message, Message.STATUS_SEND_FAILED); + FileBackend.close(mFileInputStream); + } } public void init(Message message, boolean delay) { diff --git a/src/main/java/eu/siacs/conversations/parser/AbstractParser.java b/src/main/java/eu/siacs/conversations/parser/AbstractParser.java index 03f19ed82..c14a7eb0d 100644 --- a/src/main/java/eu/siacs/conversations/parser/AbstractParser.java +++ b/src/main/java/eu/siacs/conversations/parser/AbstractParser.java @@ -51,12 +51,16 @@ public abstract class AbstractParser { return dateFormat.parse(timestamp); } - protected void updateLastseen(long timestamp, final Account account, final Jid from) { - final String presence = from == null || from.isBareJid() ? "" : from.getResourcepart(); - final Contact contact = account.getRoster().getContact(from); + protected void updateLastseen(final AbstractStanza packet, final Account account, final boolean presenceOverwrite) { + updateLastseen(getTimestamp(packet), account, packet.getFrom(), presenceOverwrite); + } + + protected void updateLastseen(long timestamp, final Account account, final Jid from, final boolean presenceOverwrite) { + final String presence = from == null || from.isBareJid() ? "" : from.getResourcepart(); + final Contact contact = account.getRoster().getContact(from); if (timestamp >= contact.lastseen.time) { contact.lastseen.time = timestamp; - if (!presence.isEmpty()) { + if (!presence.isEmpty() && presenceOverwrite) { contact.lastseen.presence = presence; } } diff --git a/src/main/java/eu/siacs/conversations/parser/MessageParser.java b/src/main/java/eu/siacs/conversations/parser/MessageParser.java index 48862c47c..887b9124a 100644 --- a/src/main/java/eu/siacs/conversations/parser/MessageParser.java +++ b/src/main/java/eu/siacs/conversations/parser/MessageParser.java @@ -12,7 +12,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.List; -import java.util.Locale; import java.util.Set; import java.util.UUID; @@ -435,11 +434,14 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece if (conversationMultiMode) { Jid trueCounterpart = conversation.getMucOptions().getTrueCounterpart(counterpart); message.setTrueCounterpart(trueCounterpart); + if (trueCounterpart != null) { + updateLastseen(timestamp, account, trueCounterpart, false); + } if (!isTypeGroupChat) { message.setType(Message.TYPE_PRIVATE); } } else { - updateLastseen(timestamp, account, from); + updateLastseen(timestamp, account, packet.getFrom(), true); } if (replacementId != null && mXmppConnectionService.allowMessageCorrection()) { @@ -601,7 +603,7 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece mXmppConnectionService.markRead(conversation); } } else { - updateLastseen(timestamp, account, from); + updateLastseen(timestamp, account, packet.getFrom(), true); final Message displayedMessage = mXmppConnectionService.markMessage(account, from.toBareJid(), displayed.getAttribute("id"), Message.STATUS_SEND_DISPLAYED); Message message = displayedMessage == null ? null : displayedMessage.prev(); while (message != null diff --git a/src/main/java/eu/siacs/conversations/parser/PresenceParser.java b/src/main/java/eu/siacs/conversations/parser/PresenceParser.java index b5718b612..89f294e90 100644 --- a/src/main/java/eu/siacs/conversations/parser/PresenceParser.java +++ b/src/main/java/eu/siacs/conversations/parser/PresenceParser.java @@ -5,7 +5,6 @@ import android.util.Log; import java.util.ArrayList; import java.util.List; - import eu.siacs.conversations.Config; import eu.siacs.conversations.crypto.PgpEngine; import eu.siacs.conversations.entities.Account; @@ -214,6 +213,7 @@ public class PresenceParser extends AbstractParser implements contact.setPgpKeyId(pgp.fetchKeyId(account, msg, x.getContent())); } boolean online = sizeBefore < contact.getPresences().size(); + updateLastseen(packet, account, false); mXmppConnectionService.onContactStatusChanged.onContactStatusChanged(contact, online); } else if (type.equals("unavailable")) { if (from.isBareJid()) { diff --git a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java index f1155b07d..f7a26cf63 100644 --- a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java +++ b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java @@ -11,6 +11,7 @@ import android.util.Base64; import android.util.Log; import android.util.Pair; +import org.json.JSONException; import org.whispersystems.libaxolotl.AxolotlAddress; import org.whispersystems.libaxolotl.IdentityKey; import org.whispersystems.libaxolotl.IdentityKeyPair; @@ -31,7 +32,6 @@ import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; -import org.json.JSONException; import eu.siacs.conversations.Config; import eu.siacs.conversations.crypto.axolotl.AxolotlService; @@ -51,7 +51,7 @@ public class DatabaseBackend extends SQLiteOpenHelper { private static DatabaseBackend instance = null; - private static final String DATABASE_NAME = "history"; + public static final String DATABASE_NAME = "history"; private static final int DATABASE_VERSION = 27; private static String CREATE_CONTATCS_STATEMENT = "create table " diff --git a/src/main/java/eu/siacs/conversations/persistance/FileBackend.java b/src/main/java/eu/siacs/conversations/persistance/FileBackend.java index db48c8b3d..64157b597 100644 --- a/src/main/java/eu/siacs/conversations/persistance/FileBackend.java +++ b/src/main/java/eu/siacs/conversations/persistance/FileBackend.java @@ -54,7 +54,7 @@ import eu.siacs.conversations.utils.FileUtils; import eu.siacs.conversations.xmpp.pep.Avatar; public class FileBackend { - private final SimpleDateFormat imageDateFormat = new SimpleDateFormat("yyyyMMdd_HHmmssSSS", Locale.US); + private final SimpleDateFormat fileDateFormat = new SimpleDateFormat("yyyyMMdd_HHmmssSSS", Locale.US); private XmppConnectionService mXmppConnectionService; @@ -74,7 +74,8 @@ public class FileBackend { } public void updateMediaScanner(File file) { - if (file.getAbsolutePath().startsWith(getConversationsImageDirectory())) { + if (file.getAbsolutePath().startsWith(getConversationsImageDirectory()) + || file.getAbsolutePath().startsWith(getConversationsVideoDirectory())) { Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE); intent.setData(Uri.fromFile(file)); mXmppConnectionService.sendBroadcast(intent); @@ -104,19 +105,24 @@ public class FileBackend { final DownloadableFile file; String path = message.getRelativeFilePath(); if (path == null) { - path = message.getUuid(); - } - if (path.startsWith("/")) { - file = new DownloadableFile(path); - } else { - String mime = message.getMimeType(); - if (mime != null && mime.startsWith("image")) { - file = new DownloadableFile(getConversationsImageDirectory() + path); - } else { - file = new DownloadableFile(getConversationsFileDirectory() + path); - } - } - if (encrypted) { + String filename = fileDateFormat.format(new Date(message.getTimeSent())); + path = filename; + } + if (path.startsWith("/")) { + file = new DownloadableFile(path); + } else { + String mime = message.getMimeType(); + if (mime != null && mime.startsWith("image")) { + file = new DownloadableFile(getConversationsImageDirectory() + path); + } else if (mime != null && mime.startsWith("video")) { + file = new DownloadableFile(getConversationsVideoDirectory() + path); + } else if (mime != null && mime.startsWith("audio")) { + file = new DownloadableFile(getConversationsAudioDirectory() + path); + } else { + file = new DownloadableFile(getConversationsFileDirectory() + path); + } + } + if (encrypted) { return new DownloadableFile(getConversationsFileDirectory() + file.getName() + ".pgp"); } else { return file; @@ -147,13 +153,19 @@ public class FileBackend { } public static String getConversationsFileDirectory() { - return Environment.getExternalStorageDirectory().getAbsolutePath()+"/Conversations/"; + return Environment.getExternalStorageDirectory().getAbsolutePath()+"/Pix-Art Messenger/files/"; } public static String getConversationsImageDirectory() { - return Environment.getExternalStoragePublicDirectory( - Environment.DIRECTORY_PICTURES).getAbsolutePath() - + "/Conversations/"; + return Environment.getExternalStorageDirectory().getAbsolutePath()+"/Pix-Art Messenger/images/"; + } + + public static String getConversationsVideoDirectory() { + return Environment.getExternalStorageDirectory().getAbsolutePath()+"/Pix-Art Messenger/videos/"; + } + + public static String getConversationsAudioDirectory() { + return Environment.getExternalStorageDirectory().getAbsolutePath()+"/Pix-Art Messenger/audios/"; } public Bitmap resize(Bitmap originalBitmap, int size) { @@ -251,7 +263,8 @@ public class FileBackend { Log.d(Config.LOGTAG, "copy " + uri.toString() + " to private storage"); String mime = mXmppConnectionService.getContentResolver().getType(uri); String extension = MimeTypeMap.getSingleton().getExtensionFromMimeType(mime); - message.setRelativeFilePath(message.getUuid() + "." + extension); + String filename = fileDateFormat.format(new Date(message.getTimeSent())); + message.setRelativeFilePath(filename + "." + extension); copyFileToPrivateStorage(mXmppConnectionService.getFileBackend().getFile(message), uri); } @@ -316,15 +329,16 @@ public class FileBackend { } public void copyImageToPrivateStorage(Message message, Uri image) throws FileCopyException { + String filename = fileDateFormat.format(new Date(message.getTimeSent())); switch(Config.IMAGE_FORMAT) { case JPEG: - message.setRelativeFilePath(message.getUuid()+".jpg"); + message.setRelativeFilePath(filename+".jpg"); break; case PNG: - message.setRelativeFilePath(message.getUuid()+".png"); + message.setRelativeFilePath(filename+".png"); break; case WEBP: - message.setRelativeFilePath(message.getUuid()+".webp"); + message.setRelativeFilePath(filename+".webp"); break; } copyImageToPrivateStorage(getFile(message), image); @@ -378,7 +392,7 @@ public class FileBackend { pathBuilder.append('/'); pathBuilder.append("Camera"); pathBuilder.append('/'); - pathBuilder.append("IMG_" + this.imageDateFormat.format(new Date()) + ".jpg"); + pathBuilder.append("IMG_" + this.fileDateFormat.format(new Date()) + ".jpg"); Uri uri = Uri.parse("file://" + pathBuilder.toString()); File file = new File(uri.toString()); file.getParentFile().mkdirs(); diff --git a/src/main/java/eu/siacs/conversations/services/AbstractConnectionManager.java b/src/main/java/eu/siacs/conversations/services/AbstractConnectionManager.java index 8d02f975a..50bb83d30 100644 --- a/src/main/java/eu/siacs/conversations/services/AbstractConnectionManager.java +++ b/src/main/java/eu/siacs/conversations/services/AbstractConnectionManager.java @@ -46,11 +46,11 @@ public class AbstractConnectionManager { public long getAutoAcceptFileSize() { String config = this.mXmppConnectionService.getPreferences().getString( - "auto_accept_file_size", "524288"); + "auto_accept_file_size", "1048576"); try { return Long.parseLong(config); } catch (NumberFormatException e) { - return 524288; + return 1048576; } } diff --git a/src/main/java/eu/siacs/conversations/services/AvatarService.java b/src/main/java/eu/siacs/conversations/services/AvatarService.java index 9e8e6970a..88071f500 100644 --- a/src/main/java/eu/siacs/conversations/services/AvatarService.java +++ b/src/main/java/eu/siacs/conversations/services/AvatarService.java @@ -49,12 +49,12 @@ public class AvatarService implements OnAdvancedStreamFeaturesLoaded { 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); } @@ -335,12 +335,22 @@ public class AvatarService implements OnAdvancedStreamFeaturesLoaded { 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 (drawTile(canvas, uri, left, top, right, bottom)) { + return true; + } + } else if (user.getAvatar() != null) { + Uri uri = mXmppConnectionService.getFileBackend().getAvatarUri(user.getAvatar()); + if (drawTile(canvas, uri, left, top, right, bottom)) { + return true; } + } else if (user.getAvatar() != null) { + Uri uri = mXmppConnectionService.getFileBackend().getAvatarUri(user.getAvatar()); if (drawTile(canvas, uri, left, top, right, bottom)) { return true; } 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..dc57745f1 --- /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("filesize", ""); + myObj.addProperty("appURI", ""); + out.println(myObj.toString()); + out.close(); + + } + +} diff --git a/src/main/java/eu/siacs/conversations/services/ContactChooserTargetService.java b/src/main/java/eu/siacs/conversations/services/ContactChooserTargetService.java index 0a8ac98ca..edc661b79 100644 --- a/src/main/java/eu/siacs/conversations/services/ContactChooserTargetService.java +++ b/src/main/java/eu/siacs/conversations/services/ContactChooserTargetService.java @@ -1,7 +1,6 @@ package eu.siacs.conversations.services; import android.annotation.TargetApi; -import android.app.PendingIntent; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -11,11 +10,8 @@ import android.graphics.drawable.Icon; import android.os.Build; import android.os.Bundle; import android.os.IBinder; -import android.os.SystemClock; import android.service.chooser.ChooserTarget; import android.service.chooser.ChooserTargetService; -import android.util.DisplayMetrics; -import android.util.Log; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/eu/siacs/conversations/services/ExportLogsService.java b/src/main/java/eu/siacs/conversations/services/ExportLogsService.java index 87e65931b..53d0caaff 100644 --- a/src/main/java/eu/siacs/conversations/services/ExportLogsService.java +++ b/src/main/java/eu/siacs/conversations/services/ExportLogsService.java @@ -6,6 +6,7 @@ import android.content.Context; import android.content.Intent; import android.os.IBinder; import android.support.v4.app.NotificationCompat; + import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; diff --git a/src/main/java/eu/siacs/conversations/services/NotificationService.java b/src/main/java/eu/siacs/conversations/services/NotificationService.java index 764a1d525..f9da1ee95 100644 --- a/src/main/java/eu/siacs/conversations/services/NotificationService.java +++ b/src/main/java/eu/siacs/conversations/services/NotificationService.java @@ -212,7 +212,7 @@ public class NotificationService { mBuilder.setSmallIcon(R.drawable.ic_notification); mBuilder.setDeleteIntent(createDeleteIntent()); if (led) { - mBuilder.setLights(0xff00FF00, 2000, 3000); + mBuilder.setLights(0xff0080FF, 2000, 3000); } final Notification notification = mBuilder.build(); notificationManager.notify(NOTIFICATION_ID, notification); @@ -304,7 +304,7 @@ public class NotificationService { 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 @@ -544,7 +544,7 @@ public class NotificationService { cancelIcon = R.drawable.ic_action_cancel; } mBuilder.setSmallIcon(R.drawable.ic_link_white_24dp); - if (Config.SHOW_DISABLE_FOREGROUND) { + if (Config.SHOW_DISABLE_FOREGROUND && !Config.USE_ALWAYS_FOREGROUND) { mBuilder.addAction(cancelIcon, mXmppConnectionService.getString(R.string.disable_foreground_service), createDisableForeground()); @@ -564,7 +564,7 @@ public class NotificationService { errors.add(account); } } - if (mXmppConnectionService.getPreferences().getBoolean("keep_foreground_service", false)) { + if (Config.USE_ALWAYS_FOREGROUND) { notificationManager.notify(FOREGROUND_NOTIFICATION_ID, createForegroundNotification()); } final NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(mXmppConnectionService); @@ -582,9 +582,11 @@ public class NotificationService { mXmppConnectionService.getString(R.string.try_again), createTryAgainIntent()); if (errors.size() == 1) { - mBuilder.addAction(R.drawable.ic_block_white_24dp, - mXmppConnectionService.getString(R.string.disable_account), - createDisableAccountIntent(errors.get(0))); + if (Config.SHOW_DISABLE_FOREGROUND && !Config.USE_ALWAYS_FOREGROUND) { + mBuilder.addAction(R.drawable.ic_block_white_24dp, + mXmppConnectionService.getString(R.string.disable_account), + createDisableAccountIntent(errors.get(0))); + } } mBuilder.setOngoing(true); //mBuilder.setLights(0xffffffff, 2000, 4000); 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..d7044d73a --- /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.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + 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/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 06ecb22b9..79f4d51f3 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -20,7 +20,6 @@ import android.os.Build; import android.os.Bundle; import android.os.FileObserver; import android.os.IBinder; -import android.os.Looper; import android.os.PowerManager; import android.os.PowerManager.WakeLock; import android.os.SystemClock; @@ -520,10 +519,6 @@ public class XmppConnectionService extends Service { case ACTION_CLEAR_NOTIFICATION: mNotificationService.clear(); break; - case ACTION_DISABLE_FOREGROUND: - getPreferences().edit().putBoolean("keep_foreground_service", false).commit(); - toggleForegroundService(); - break; case ACTION_TRY_AGAIN: resetAllAttemptCounts(false); interactive = true; @@ -808,7 +803,7 @@ public class XmppConnectionService extends Service { } public void toggleForegroundService() { - if (getPreferences().getBoolean("keep_foreground_service", false)) { + if (Config.USE_ALWAYS_FOREGROUND) { startForeground(NotificationService.FOREGROUND_NOTIFICATION_ID, this.mNotificationService.createForegroundNotification()); } else { stopForeground(true); @@ -2782,11 +2777,11 @@ public class XmppConnectionService extends Service { } public boolean allowMessageCorrection() { - return getPreferences().getBoolean("allow_message_correction", false); + return getPreferences().getBoolean("allow_message_correction", true); } public boolean sendChatStates() { - return getPreferences().getBoolean("chat_states", false); + return getPreferences().getBoolean("chat_states", true); } public boolean saveEncryptedMessages() { @@ -2798,7 +2793,7 @@ public class XmppConnectionService extends Service { } public boolean indicateReceived() { - return getPreferences().getBoolean("indicate_received", false); + return getPreferences().getBoolean("indicate_received", true); } public boolean useTorToConnect() { diff --git a/src/main/java/eu/siacs/conversations/ui/AboutPreference.java b/src/main/java/eu/siacs/conversations/ui/AboutPreference.java index bd2042fb6..451f0bfa6 100644 --- a/src/main/java/eu/siacs/conversations/ui/AboutPreference.java +++ b/src/main/java/eu/siacs/conversations/ui/AboutPreference.java @@ -26,7 +26,7 @@ public class AboutPreference extends Preference { } private void setSummary() { - setSummary("Conversations " + PhoneHelper.getVersionName(getContext())); + setSummary("Pix-Art Messenger " + PhoneHelper.getVersionName(getContext())); } } diff --git a/src/main/java/eu/siacs/conversations/ui/ChangePasswordActivity.java b/src/main/java/eu/siacs/conversations/ui/ChangePasswordActivity.java index 3fb756308..31c85c19d 100644 --- a/src/main/java/eu/siacs/conversations/ui/ChangePasswordActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ChangePasswordActivity.java @@ -11,8 +11,6 @@ import android.widget.Toast; import eu.siacs.conversations.R; import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.services.XmppConnectionService; -import eu.siacs.conversations.xmpp.jid.InvalidJidException; -import eu.siacs.conversations.xmpp.jid.Jid; public class ChangePasswordActivity extends XmppActivity implements XmppConnectionService.OnAccountPasswordChanged { @@ -121,4 +119,4 @@ public class ChangePasswordActivity extends XmppActivity implements XmppConnecti public void refreshUiReal() { } -} +}
\ 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 a82f82458..9f3602ffb 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java @@ -18,7 +18,6 @@ import android.widget.Button; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.LinearLayout; -import android.widget.TableLayout; import android.widget.TextView; import android.widget.Toast; @@ -61,7 +60,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers private LinearLayout membersView; private LinearLayout mMoreDetails; private TextView mConferenceType; - private TableLayout mConferenceInfoTable; + private LinearLayout mConferenceInfoTable; private TextView mConferenceInfoMam; private TextView mNotifyStatusText; private ImageButton mChangeConferenceSettingsButton; @@ -262,7 +261,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers } }); this.mAdvancedMode = getPreferences().getBoolean("advanced_muc_mode", false); - this.mConferenceInfoTable = (TableLayout) findViewById(R.id.muc_info_more); + this.mConferenceInfoTable = (LinearLayout) findViewById(R.id.muc_info_more); mConferenceInfoTable.setVisibility(this.mAdvancedMode ? View.VISIBLE : View.GONE); this.mConferenceInfoMam = (TextView) findViewById(R.id.muc_info_mam); this.mNotifyStatusButton = (ImageButton) findViewById(R.id.notification_status_button); diff --git a/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java b/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java index de0979a60..4f2f5e7b2 100644 --- a/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ContactDetailsActivity.java @@ -2,6 +2,7 @@ package eu.siacs.conversations.ui; import android.app.AlertDialog; import android.app.PendingIntent; +import android.content.ActivityNotFoundException; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; @@ -41,8 +42,8 @@ import eu.siacs.conversations.crypto.axolotl.AxolotlService; import eu.siacs.conversations.crypto.axolotl.XmppAxolotlSession; import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.Contact; +import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.entities.ListItem; -import eu.siacs.conversations.entities.Presence; import eu.siacs.conversations.services.XmppConnectionService.OnAccountUpdate; import eu.siacs.conversations.services.XmppConnectionService.OnRosterUpdate; import eu.siacs.conversations.utils.CryptoHelper; @@ -56,6 +57,7 @@ import eu.siacs.conversations.xmpp.jid.Jid; public class ContactDetailsActivity extends XmppActivity implements OnAccountUpdate, OnRosterUpdate, OnUpdateBlocklist, OnKeyStatusUpdated { public static final String ACTION_VIEW_CONTACT = "view_contact"; + private Conversation mConversation; private Contact contact; private DialogInterface.OnClickListener removeFromRoster = new DialogInterface.OnClickListener() { @@ -107,6 +109,7 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd private Jid contactJid; private TextView contactJidTv; private TextView accountJidTv; + private TextView lastseen; private TextView statusMessage; private CheckBox send; private CheckBox receive; @@ -203,6 +206,7 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd contactJidTv = (TextView) findViewById(R.id.details_contactjid); accountJidTv = (TextView) findViewById(R.id.details_account); + lastseen = (TextView) findViewById(R.id.details_lastseen); statusMessage = (TextView) findViewById(R.id.status_message); send = (CheckBox) findViewById(R.id.details_send_presence); receive = (CheckBox) findViewById(R.id.details_receive_presence); @@ -225,6 +229,18 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd this.showDynamicTags = preferences.getBoolean("show_dynamic_tags",false); } + private void share() { + Intent shareIntent = new Intent(); + shareIntent.setAction(Intent.ACTION_SEND); + shareIntent.putExtra(Intent.EXTRA_TEXT, getShareableUri()); + shareIntent.setType("text/plain"); + try { + startActivity(Intent.createChooser(shareIntent, getText(R.string.share_uri_with))); + } catch (ActivityNotFoundException e) { + Toast.makeText(this, R.string.no_application_to_share_uri, Toast.LENGTH_SHORT).show(); + } + } + @Override public boolean onOptionsItemSelected(final MenuItem menuItem) { final AlertDialog.Builder builder = new AlertDialog.Builder(this); @@ -263,6 +279,9 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd startActivity(intent); } break; + case R.id.action_share: + share(); + break; case R.id.action_block: BlockContactDialog.show(this, xmppConnectionService, contact); break; @@ -371,6 +390,12 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd statusMessage.setVisibility(View.GONE); } + if (contact.isBlocked() && !this.showDynamicTags) { + lastseen.setText(R.string.contact_blocked); + } else { + lastseen.setText(UIHelper.lastseen(getApplicationContext(), contact.lastseen.time)); + } + if (contact.getPresences().size() > 1) { contactJidTv.setText(contact.getDisplayJid() + " (" + contact.getPresences().size() + ")"); @@ -384,7 +409,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 a9b9beb72..4d9aa8d6c 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java @@ -7,11 +7,16 @@ import android.app.FragmentTransaction; import android.app.PendingIntent; import android.content.ActivityNotFoundException; 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.content.pm.ApplicationInfo; +import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +import android.graphics.Typeface; import android.net.Uri; import android.os.Build; import android.os.Bundle; @@ -33,6 +38,7 @@ import android.widget.ArrayAdapter; import android.widget.CheckBox; import android.widget.PopupMenu; import android.widget.PopupMenu.OnMenuItemClickListener; +import android.widget.TextView; import android.widget.Toast; import net.java.otr4j.session.SessionStatus; @@ -54,6 +60,7 @@ 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.Presence; import eu.siacs.conversations.entities.Transferable; import eu.siacs.conversations.persistance.FileBackend; import eu.siacs.conversations.services.XmppConnectionService; @@ -62,12 +69,14 @@ import eu.siacs.conversations.services.XmppConnectionService.OnConversationUpdat 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 { + implements OnAccountUpdate, OnConversationUpdate, OnRosterUpdate, OnUpdateBlocklist, XmppConnectionService.OnShowErrorToast, View.OnClickListener { public static final String ACTION_DOWNLOAD = "eu.siacs.conversations.action.DOWNLOAD"; @@ -93,11 +102,10 @@ public class ConversationActivity extends XmppActivity 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 String mOpenConverstaion = null; + private boolean mPanelOpen = true; private Uri mPendingGeoUri = null; private boolean forbidProcessingPendings = false; private Message mPendingDownloadableMessage = null; @@ -118,6 +126,24 @@ public class ConversationActivity extends XmppActivity private AtomicBoolean mRedirected = new AtomicBoolean(false); private Pair<Integer, Intent> mPostponedActivityResult; + @SuppressLint("NewApi") + private static List<Uri> extractUriFromIntent(final Intent intent) { + List<Uri> uris = new ArrayList<>(); + if (intent == null) { + return uris; + } + 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; + } + public Conversation getSelectedConversation() { return this.mSelectedConversation; } @@ -274,11 +300,12 @@ public class ConversationActivity extends XmppActivity }; } }); - listView.enableSwipeToDismiss(); + //listView.enableSwipeToDismiss(); listView.setSwipingLayout(R.id.swipeable_item); listView.setUndoStyle(EnhancedListView.UndoStyle.SINGLE_POPUP); - listView.setUndoHideDelay(5000); + 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) { @@ -319,6 +346,99 @@ public class ConversationActivity extends XmppActivity } } + private boolean isPackageInstalled(String targetPackage){ + List<ApplicationInfo> packages; + PackageManager pm; + pm = getPackageManager(); + packages = pm.getInstalledApplications(0); + for (ApplicationInfo packageInfo : packages) { + if(packageInfo.packageName.equals(targetPackage)) return true; + } + return false; + } + + protected void AppUpdate() { + String PREFS_NAME = "UpdateTimeStamp"; + SharedPreferences UpdateTimeStamp = getApplicationContext().getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE); + long lastUpdateTime = UpdateTimeStamp.getLong("lastUpdateTime", 0); + + //detect installed plugins and deinstall them + PackageInfo pInfo = null; + try { + pInfo = getPackageManager().getPackageInfo(getPackageName(), 0); + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + } + //get the app version Name for display + final int versionCode = pInfo.versionCode; + // delete voice recorder and location plugin for versions >= 142 (1.12.1) + if (versionCode >= 142) { + Log.d(Config.LOGTAG, "New Features - Uninstall plugins"); + if (isPackageInstalled("eu.siacs.conversations.voicerecorder") || isPackageInstalled("eu.siacs.conversations.sharelocation") || isPackageInstalled("com.samwhited.opensharelocationplugin")) { + AlertDialog.Builder builder = new AlertDialog.Builder(ConversationActivity.this); + builder.setMessage(R.string.uninstall_plugins) + .setPositiveButton(R.string.uninstall, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialogInterface, int i) { + //start the deinstallation of voice recorder + if (isPackageInstalled("eu.siacs.conversations.voicerecorder")) { + Uri packageURI_VR = Uri.parse("package:eu.siacs.conversations.voicerecorder"); + Intent uninstallIntent_VR = new Intent(Intent.ACTION_UNINSTALL_PACKAGE, packageURI_VR); + if (uninstallIntent_VR.resolveActivity(getPackageManager()) != null) { + Log.d(Config.LOGTAG, "New Features - Uninstall voice recorder"); + startActivity(uninstallIntent_VR); + } + } + //start the deinstallation of share location + if (isPackageInstalled("eu.siacs.conversations.sharelocation")) { + Uri packageURI_SL = Uri.parse("package:eu.siacs.conversations.sharelocation"); + Intent uninstallIntent_SL = new Intent(Intent.ACTION_UNINSTALL_PACKAGE, packageURI_SL); + if (uninstallIntent_SL.resolveActivity(getPackageManager()) != null) { + Log.d(Config.LOGTAG, "New Features - Uninstall share location"); + startActivity(uninstallIntent_SL); + } + } + //start the deinstallation of open share location + if (isPackageInstalled("com.samwhited.opensharelocationplugin")) { + Uri packageURI_SL = Uri.parse("package:com.samwhited.opensharelocationplugin"); + Intent uninstallIntent_SL = new Intent(Intent.ACTION_UNINSTALL_PACKAGE, packageURI_SL); + if (uninstallIntent_SL.resolveActivity(getPackageManager()) != null) { + Log.d(Config.LOGTAG, "New Features - Uninstall open share location"); + startActivity(uninstallIntent_SL); + } + } + } + }) + .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialogInterface, int i) { + Log.d(Config.LOGTAG, "New Features - Uninstall cancled"); + + } + }); + builder.create().show(); + } + } + + 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); @@ -336,24 +456,70 @@ public class ConversationActivity extends XmppActivity } 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); - } - } - } + final ActionBar ab = getActionBar(); + final Conversation conversation = getSelectedConversation(); + if (ab != null) { + if (titleShouldBeName && conversation != null) { + ab.setDisplayHomeAsUpEnabled(true); + ab.setHomeButtonEnabled(true); + ab.setDisplayShowTitleEnabled(false); + ab.setDisplayShowCustomEnabled(true); + ab.setCustomView(R.layout.ab_title); + if (conversation.getMode() == Conversation.MODE_SINGLE || useSubjectToIdentifyConference()) { + TextView abtitle = (TextView) findViewById(android.R.id.text1); + abtitle.setText(conversation.getName()); + abtitle.setOnClickListener(this); + if (conversation.getMode() == Conversation.MODE_SINGLE && !this.getSelectedConversation().withSelf()) { + if (conversation.getContact().getMostAvailableStatus() == Presence.Status.OFFLINE) { + TextView absubtitle = (TextView) findViewById(android.R.id.text2); + absubtitle.setText(getString(R.string.account_status_offline)); + absubtitle.setOnClickListener(this); + } else { + ChatState state = conversation.getIncomingChatState(); + if (state == ChatState.COMPOSING) { + TextView absubtitle = (TextView) findViewById(android.R.id.text2); + absubtitle.setText(getString(R.string.is_typing)); + absubtitle.setTypeface(null, Typeface.BOLD_ITALIC); + absubtitle.setOnClickListener(this); + } else if (state == ChatState.PAUSED) { + TextView absubtitle = (TextView) findViewById(android.R.id.text2); + absubtitle.setText(UIHelper.lastseen(getApplicationContext(), conversation.getContact().lastseen.time)); + absubtitle.setOnClickListener(this); + } else { + TextView absubtitle = (TextView) findViewById(android.R.id.text2); + absubtitle.setText(UIHelper.lastseen(getApplicationContext(), conversation.getContact().lastseen.time)); + absubtitle.setOnClickListener(this); + } + } + } else if (useSubjectToIdentifyConference()) { + if (conversation.getParticipants() != null) { + TextView absubtitle = (TextView) findViewById(android.R.id.text2); + absubtitle.setText(conversation.getParticipants()); + absubtitle.setOnClickListener(this); + } else { + TextView absubtitle = (TextView) findViewById(android.R.id.text2); + absubtitle.setText(R.string.no_participants); + absubtitle.setOnClickListener(this); + } + } + } else { + TextView abtitle = (TextView) findViewById(android.R.id.text1); + abtitle.setText(conversation.getJid().toBareJid().toString()); + abtitle.setOnClickListener(this); + TextView absubtitle = (TextView) findViewById(android.R.id.text2); + absubtitle.setText(null); + absubtitle.setOnClickListener(this); + } + } else { + ab.setDisplayHomeAsUpEnabled(false); + ab.setHomeButtonEnabled(false); + ab.setDisplayShowTitleEnabled(true); + ab.setDisplayShowCustomEnabled(false); + ab.setTitle(R.string.app_name); + ab.setSubtitle(null); + } + } + } private void openConversation() { this.updateActionBarTitle(); @@ -376,20 +542,20 @@ public class ConversationActivity extends XmppActivity 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 menuArchiveChat = menu.findItem(R.id.action_archive_chat); + final MenuItem menuArchiveMuc = menu.findItem(R.id.action_archive_muc); 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); + final MenuItem menuUpdater = menu.findItem(R.id.action_check_updates); + final MenuItem menuInviteUser = menu.findItem(R.id.action_invite_user); if (isConversationsOverviewVisable() && isConversationsOverviewHideable()) { - menuArchive.setVisible(false); - menuMucDetails.setVisible(false); - menuContactDetails.setVisible(false); + menuArchiveChat.setVisible(false); + menuArchiveMuc.setVisible(false); menuSecure.setVisible(false); menuInviteContact.setVisible(false); menuAttach.setVisible(false); @@ -398,7 +564,16 @@ public class ConversationActivity extends XmppActivity menuUnmute.setVisible(false); } else { menuAdd.setVisible(!isConversationsOverviewHideable()); + //hide settings, accounts and updater in all menus except in main window + menuUpdater.setVisible(false); + menuInviteUser.setVisible(false); + if (this.getSelectedConversation() != null) { + if (this.getSelectedConversation().getMode() == Conversation.MODE_SINGLE) { + menuArchiveMuc.setVisible(false); + } else { + menuArchiveChat.setVisible(false); + } if (this.getSelectedConversation().getNextEncryption() != Message.ENCRYPTION_NONE) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { menuSecure.setIcon(R.drawable.ic_lock_white_24dp); @@ -407,13 +582,10 @@ public class ConversationActivity extends XmppActivity } } 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.supportOpenPgp() || Config.supportOmemo()) && Config.multipleEncryptionChoices()); //only if pgp is supported we have a choice } else { - menuContactDetails.setVisible(!this.getSelectedConversation().withSelf()); - menuMucDetails.setVisible(false); menuSecure.setVisible(Config.multipleEncryptionChoices()); } if (this.getSelectedConversation().isMuted()) { @@ -458,11 +630,11 @@ public class ConversationActivity extends XmppActivity 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: + case ATTACHMENT_CHOICE_RECORD_VOICE: + intent.setAction(MediaStore.Audio.Media.RECORD_SOUND_ACTION); + intent.setPackage("eu.siacs.conversations"); + break; + case ATTACHMENT_CHOICE_LOCATION: intent.setAction("eu.siacs.conversations.location.request"); fallbackPackageId = "eu.siacs.conversations.sharelocation"; break; @@ -627,10 +799,24 @@ public class ConversationActivity extends XmppActivity case R.id.action_attach_file: attachFileDialog(); break; - case R.id.action_archive: + case R.id.action_archive_chat: this.endConversation(getSelectedConversation()); break; - case R.id.action_contact_details: + case R.id.action_archive_muc: + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle(getString(R.string.action_end_conversation_muc)); + builder.setMessage(getString(R.string.leave_conference_warning)); + builder.setNegativeButton(getString(R.string.cancel), null); + builder.setPositiveButton(getString(R.string.action_end_conversation_muc), + new OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + endConversation(getSelectedConversation()); + } + }); + builder.create().show(); + break; +/* case R.id.action_contact_details: switchToContactDetails(getSelectedConversation().getContact()); break; case R.id.action_muc_details: @@ -640,6 +826,7 @@ public class ConversationActivity extends XmppActivity intent.putExtra("uuid", getSelectedConversation().getUuid()); startActivity(intent); break; +*/ case R.id.action_invite: inviteToConversation(getSelectedConversation()); break; @@ -701,8 +888,11 @@ public class ConversationActivity extends XmppActivity 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); + final CheckBox endConversationCheckBox = (CheckBox) dialogView + .findViewById(R.id.end_conversation_checkbox); + if (conversation.getMode() == Conversation.MODE_SINGLE) { + endConversationCheckBox.setVisibility(View.VISIBLE); + } builder.setView(dialogView); builder.setNegativeButton(getString(R.string.cancel), null); builder.setPositiveButton(getString(R.string.delete_messages), @@ -711,12 +901,17 @@ public class ConversationActivity extends XmppActivity @Override public void onClick(DialogInterface dialog, int which) { ConversationActivity.this.xmppConnectionService.clearConversationHistory(conversation); - if (endConversationCheckBox.isChecked()) { - endConversation(conversation); - } else { - updateConversationList(); - ConversationActivity.this.mConversationFragment.updateMessages(); - } + if (conversation.getMode() == Conversation.MODE_SINGLE) { + if (endConversationCheckBox.isChecked()) { + endConversation(conversation); + } else { + updateConversationList(); + ConversationActivity.this.mConversationFragment.updateMessages(); + } + } else { + updateConversationList(); + ConversationActivity.this.mConversationFragment.updateMessages(); + } } }); builder.create().show(); @@ -959,8 +1154,7 @@ public class ConversationActivity extends XmppActivity } else if (modifier && key == downKey) { if (isConversationsOverviewHideable() && !isConversationsOverviewVisable()) { showConversationsOverview(); - ; - } + } return selectDownConversation(); } else if (modifier && key == upKey) { if (isConversationsOverviewHideable() && !isConversationsOverviewVisable()) { @@ -1088,7 +1282,6 @@ public class ConversationActivity extends XmppActivity if (!isConversationsOverviewVisable() || !isConversationsOverviewHideable()) { sendReadMarkerIfNecessary(getSelectedConversation()); } - } @Override @@ -1175,6 +1368,10 @@ public class ConversationActivity extends XmppActivity this.mConversationFragment.setupIme(); } + if (xmppConnectionService.getAccounts().size() != 0) { + AppUpdate(); + } + if (this.mPostponedActivityResult != null) { this.onActivityResult(mPostponedActivityResult.first, RESULT_OK, mPostponedActivityResult.second); } @@ -1258,24 +1455,6 @@ public class ConversationActivity extends XmppActivity xmppConnectionService.getNotificationService().setOpenConversation(null); } - @SuppressLint("NewApi") - private static List<Uri> extractUriFromIntent(final Intent intent) { - List<Uri> uris = new ArrayList<>(); - if (intent == null) { - return uris; - } - 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); @@ -1431,7 +1610,7 @@ public class ConversationActivity extends XmppActivity if (conversation == null) { return; } - xmppConnectionService.attachLocationToConversation(conversation,uri, new UiCallback<Message>() { + xmppConnectionService.attachLocationToConversation(conversation, uri, new UiCallback<Message>() { @Override public void success(Message message) { @@ -1562,15 +1741,15 @@ public class ConversationActivity extends XmppActivity } public boolean useSendButtonToIndicateStatus() { - return getPreferences().getBoolean("send_button_status", false); + return getPreferences().getBoolean("send_button_status", true); } public boolean indicateReceived() { - return getPreferences().getBoolean("indicate_received", false); + return getPreferences().getBoolean("indicate_received", true); } public boolean useWhiteBackground() { - return getPreferences().getBoolean("use_white_background",false); + return getPreferences().getBoolean("use_white_background", false); } protected boolean trustKeysIfNeeded(int requestCode) { @@ -1660,6 +1839,20 @@ public class ConversationActivity extends XmppActivity return !isConversationsOverviewHideable() || this.conversationWasSelectedByKeyboard; } + @Override + public void onClick(View view) { + final Conversation conversation = getSelectedConversation(); + if (conversation.getMode() == Conversation.MODE_SINGLE) { + switchToContactDetails(getSelectedConversation().getContact()); + } else if (conversation.getMode() == Conversation.MODE_MULTI) { + Intent intent = new Intent(this, + ConferenceDetailsActivity.class); + intent.setAction(ConferenceDetailsActivity.ACTION_VIEW_MUC); + intent.putExtra("uuid", getSelectedConversation().getUuid()); + startActivity(intent); + } + } + public void setMessagesLoaded() { if (mConversationFragment != null) { mConversationFragment.setMessagesLoaded(); diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java index 8e0b30a88..6d304f15b 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java @@ -13,7 +13,6 @@ import android.os.Bundle; import android.os.Handler; import android.support.annotation.Nullable; import android.text.InputType; -import android.util.Log; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.view.Gravity; @@ -323,6 +322,16 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa } } }; + private View.OnLongClickListener mSendButtonLongListener = new View.OnLongClickListener() { + @Override + public boolean onLongClick(View v) { + final String body = mEditMessage.getText().toString(); + if (body.length() == 0) { + mEditMessage.getText().insert(0, "/me "); + } + return true; + } + }; private OnClickListener clickToMuc = new OnClickListener() { @Override @@ -451,6 +460,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa mSendButton = (ImageButton) view.findViewById(R.id.textSendButton); mSendButton.setOnClickListener(this.mSendButtonListener); + mSendButton.setOnLongClickListener(this.mSendButtonLongListener); snackbar = (RelativeLayout) view.findViewById(R.id.snackbar); snackbarMessage = (TextView) view.findViewById(R.id.snackbar_message); @@ -1139,18 +1149,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 c6251c22d..dee356c81 100644 --- a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java @@ -34,8 +34,6 @@ import android.widget.TableRow; import android.widget.TextView; import android.widget.Toast; -import android.util.Log; - import java.util.Arrays; import java.util.List; import java.util.Set; @@ -45,9 +43,9 @@ import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.crypto.axolotl.AxolotlService; import eu.siacs.conversations.entities.Account; -import eu.siacs.conversations.services.XmppConnectionService.OnCaptchaRequested; import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.services.XmppConnectionService.OnAccountUpdate; +import eu.siacs.conversations.services.XmppConnectionService.OnCaptchaRequested; import eu.siacs.conversations.ui.adapter.KnownHostsAdapter; import eu.siacs.conversations.utils.CryptoHelper; import eu.siacs.conversations.utils.UIHelper; @@ -467,7 +465,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.mNamePort = (LinearLayout) findViewById(R.id.name_port); @@ -626,6 +624,15 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate @Override public boolean onOptionsItemSelected(final MenuItem item) { switch (item.getItemId()) { + case R.id.mgmt_account_reconnect: + if (xmppConnectionServiceBound) { + unbindService(mConnection); + xmppConnectionServiceBound = false; + } + stopService(new Intent(EditAccountActivity.this, + XmppConnectionService.class)); + finish(); + break; case R.id.action_show_block_list: final Intent showBlocklistIntent = new Intent(this, BlocklistActivity.class); showBlocklistIntent.putExtra(EXTRA_ACCOUNT, mAccount.getJid().toString()); @@ -702,7 +709,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))); } else { this.mAvatar.setVisibility(View.GONE); } @@ -1035,4 +1042,4 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate } }); } -} +}
\ No newline at end of file diff --git a/src/main/java/eu/siacs/conversations/ui/ManageAccountActivity.java b/src/main/java/eu/siacs/conversations/ui/ManageAccountActivity.java index 2d29c521e..48af85947 100644 --- a/src/main/java/eu/siacs/conversations/ui/ManageAccountActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ManageAccountActivity.java @@ -21,6 +21,8 @@ import android.widget.AdapterView.OnItemClickListener; import android.widget.ListView; import android.widget.Toast; +import org.openintents.openpgp.util.OpenPgpApi; + import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; @@ -34,8 +36,6 @@ import eu.siacs.conversations.ui.adapter.AccountAdapter; import eu.siacs.conversations.xmpp.jid.InvalidJidException; import eu.siacs.conversations.xmpp.jid.Jid; -import org.openintents.openpgp.util.OpenPgpApi; - public class ManageAccountActivity extends XmppActivity implements OnAccountUpdate, KeyChainAliasCallback, XmppConnectionService.OnAccountCreated { private final String STATE_SELECTED_ACCOUNT = "selected_account"; @@ -114,16 +114,15 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, v, menuInfo); ManageAccountActivity.this.getMenuInflater().inflate( - R.menu.manageaccounts_context, menu); + R.menu.manageaccounts_context, menu); AdapterContextMenuInfo acmi = (AdapterContextMenuInfo) menuInfo; this.selectedAccount = accountList.get(acmi.position); if (this.selectedAccount.isOptionSet(Account.OPTION_DISABLED)) { - menu.findItem(R.id.mgmt_account_disable).setVisible(false); + menu.findItem(R.id.mgmt_account_reconnect).setVisible(false); menu.findItem(R.id.mgmt_account_announce_pgp).setVisible(false); menu.findItem(R.id.mgmt_account_publish_avatar).setVisible(false); menu.findItem(R.id.mgmt_account_change_presence).setVisible(false); } else { - menu.findItem(R.id.mgmt_account_enable).setVisible(false); menu.findItem(R.id.mgmt_account_announce_pgp).setVisible(Config.supportOpenPgp()); menu.findItem(R.id.mgmt_account_change_presence).setVisible(manuallyChangePresence()); } @@ -149,22 +148,16 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.manageaccounts, menu); - MenuItem enableAll = menu.findItem(R.id.action_enable_all); MenuItem addAccount = menu.findItem(R.id.action_add_account); MenuItem addAccountWithCertificate = menu.findItem(R.id.action_add_account_with_cert); if (Config.X509_VERIFICATION) { addAccount.setVisible(false); addAccountWithCertificate.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); + } else { + addAccount.setVisible(!Config.SINGLE_ACCOUNT); } - - if (!accountsLeftToEnable()) { - enableAll.setVisible(false); - } - MenuItem disableAll = menu.findItem(R.id.action_disable_all); - if (!accountsLeftToDisable()) { - disableAll.setVisible(false); - } + addAccountWithCertificate.setVisible(!Config.SINGLE_ACCOUNT); return true; } @@ -174,10 +167,8 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda case R.id.mgmt_account_publish_avatar: publishAvatar(selectedAccount); return true; - case R.id.mgmt_account_disable: + case R.id.mgmt_account_reconnect: disableAccount(selectedAccount); - return true; - case R.id.mgmt_account_enable: enableAccount(selectedAccount); return true; case R.id.mgmt_account_delete: @@ -201,12 +192,6 @@ public class ManageAccountActivity extends XmppActivity implements OnAccountUpda startActivity(new Intent(getApplicationContext(), EditAccountActivity.class)); break; - case R.id.action_disable_all: - disableAllAccounts(); - break; - case R.id.action_enable_all: - enableAllAccounts(); - break; case R.id.action_add_account_with_cert: addAccountFromKey(); break; diff --git a/src/main/java/eu/siacs/conversations/ui/PublishProfilePictureActivity.java b/src/main/java/eu/siacs/conversations/ui/PublishProfilePictureActivity.java index 0752ae321..19c1c1f68 100644 --- a/src/main/java/eu/siacs/conversations/ui/PublishProfilePictureActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/PublishProfilePictureActivity.java @@ -1,3 +1,4 @@ + package eu.siacs.conversations.ui; import android.app.PendingIntent; @@ -200,7 +201,7 @@ public class PublishProfilePictureActivity extends XmppActivity { source = Uri.parse("file://"+original); } Uri destination = Uri.fromFile(new File(getCacheDir(), "croppedAvatar")); - final int size = getPixel(192); + final int size = getPixel(Config.AVATAR_SIZE); Crop.of(source, destination).asSquare().withMaxSize(size, size).start(this); break; case REQUEST_CHOOSE_FILE: @@ -240,7 +241,7 @@ public class PublishProfilePictureActivity extends XmppActivity { if (this.avatarUri == null) { if (this.account.getAvatar() != null || this.defaultUri == null) { - this.avatar.setImageBitmap(avatarService().get(account, getPixel(192))); + this.avatar.setImageBitmap(avatarService().get(account, getPixel(Config.AVATAR_SIZE))); if (this.defaultUri != null) { this.avatar .setOnLongClickListener(this.backToDefaultListener); @@ -285,7 +286,7 @@ public class PublishProfilePictureActivity extends XmppActivity { protected void loadImageIntoPreview(Uri uri) { Bitmap bm = null; try { - bm = xmppConnectionService.getFileBackend().cropCenterSquare(uri, getPixel(192)); + bm = xmppConnectionService.getFileBackend().cropCenterSquare(uri, getPixel(Config.AVATAR_SIZE)); } catch (Exception e) { e.printStackTrace(); } diff --git a/src/main/java/eu/siacs/conversations/ui/RecordingActivity.java b/src/main/java/eu/siacs/conversations/ui/RecordingActivity.java new file mode 100644 index 000000000..ac04e1f70 --- /dev/null +++ b/src/main/java/eu/siacs/conversations/ui/RecordingActivity.java @@ -0,0 +1,158 @@ +package eu.siacs.conversations.ui; + +import android.app.Activity; +import android.content.Intent; +import android.media.MediaRecorder; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +import android.os.Environment; +import android.os.Handler; +import android.os.SystemClock; +import android.util.Log; +import android.view.View; +import android.view.WindowManager; +import android.widget.Button; +import android.widget.TextView; + +import java.io.File; +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; + +import eu.siacs.conversations.Config; +import eu.siacs.conversations.R; + +public class RecordingActivity extends Activity implements View.OnClickListener { + + private TextView mTimerTextView; + private Button mCancelButton; + private Button mStopButton; + + private MediaRecorder mRecorder; + private long mStartTime = 0; + + private int[] amplitudes = new int[100]; + private int i = 0; + + private Handler mHandler = new Handler(); + private Runnable mTickExecutor = new Runnable() { + @Override + public void run() { + tick(); + mHandler.postDelayed(mTickExecutor,100); + } + }; + private File mOutputFile; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_recording); + this.mTimerTextView = (TextView) this.findViewById(R.id.timer); + this.mCancelButton = (Button) this.findViewById(R.id.cancel_button); + this.mCancelButton.setOnClickListener(this); + this.mStopButton = (Button) this.findViewById(R.id.share_button); + this.mStopButton.setOnClickListener(this); + getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + } + + @Override + protected void onStart() { + super.onStart(); + Log.d(Config.LOGTAG, "output: " + getOutputFile()); + startRecording(); + } + + @Override + protected void onStop() { + super.onStop(); + if (mRecorder != null) { + stopRecording(false); + } + } + + private void startRecording() { + mRecorder = new MediaRecorder(); + mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); + mRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { + mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC); + mRecorder.setAudioEncodingBitRate(48000); + } else { + mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC); + mRecorder.setAudioEncodingBitRate(48000); + } + mRecorder.setAudioSamplingRate(48000); + mOutputFile = getOutputFile(); + mOutputFile.getParentFile().mkdirs(); + mRecorder.setOutputFile(mOutputFile.getAbsolutePath()); + + try { + mRecorder.prepare(); + mRecorder.start(); + mStartTime = SystemClock.elapsedRealtime(); + mHandler.postDelayed(mTickExecutor, 100); + Log.d(Config.LOGTAG,"started recording to "+mOutputFile.getAbsolutePath()); + } catch (IOException e) { + Log.e(Config.LOGTAG, "prepare() failed "+e.getMessage()); + } + } + + protected void stopRecording(boolean saveFile) { + mRecorder.stop(); + mRecorder.release(); + mRecorder = null; + mStartTime = 0; + mHandler.removeCallbacks(mTickExecutor); + if (!saveFile && mOutputFile != null) { + mOutputFile.delete(); + } + } + + private File getOutputFile() { + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_HHmmssSSS", Locale.US); + return new File(Environment.getExternalStorageDirectory().getAbsolutePath().toString() + + "/Pix-Art Messenger/Recording" + + dateFormat.format(new Date()) + + ".m4a"); + } + + private void tick() { + long time = (mStartTime < 0) ? 0 : (SystemClock.elapsedRealtime() - mStartTime); + int minutes = (int) (time / 60000); + int seconds = (int) (time / 1000) % 60; + int milliseconds = (int) (time / 100) % 10; + mTimerTextView.setText(minutes+":"+(seconds < 10 ? "0"+seconds : seconds)+"."+milliseconds); + if (mRecorder != null) { + amplitudes[i] = mRecorder.getMaxAmplitude(); + //Log.d(Config.LOGTAG,"amplitude: "+(amplitudes[i] * 100 / 32767)); + if (i >= amplitudes.length -1) { + i = 0; + } else { + ++i; + } + } + } + + @Override + public void onClick(View view) { + switch (view.getId()) { + case R.id.cancel_button: + stopRecording(false); + setResult(RESULT_CANCELED); + finish(); + break; + case R.id.share_button: + stopRecording(true); + Uri uri = Uri.parse("file://"+mOutputFile.getAbsolutePath()); + Intent scanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE); + scanIntent.setData(uri); + sendBroadcast(scanIntent); + setResult(Activity.RESULT_OK, new Intent().setData(uri)); + finish(); + break; + } + } +}
\ No newline at end of file diff --git a/src/main/java/eu/siacs/conversations/ui/SetPresenceActivity.java b/src/main/java/eu/siacs/conversations/ui/SetPresenceActivity.java index 0962d209b..ca1fb8f7c 100644 --- a/src/main/java/eu/siacs/conversations/ui/SetPresenceActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/SetPresenceActivity.java @@ -18,15 +18,8 @@ import android.widget.ScrollView; import android.widget.Spinner; import android.widget.TextView; -import android.util.Log; - -import org.openintents.openpgp.util.OpenPgpApi; - import java.util.List; -import java.util.concurrent.RunnableFuture; -import java.util.concurrent.atomic.AtomicBoolean; -import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.entities.ListItem; diff --git a/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java b/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java index cd843b259..30781e553 100644 --- a/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java @@ -14,7 +14,6 @@ import android.preference.Preference; import android.preference.PreferenceCategory; import android.preference.PreferenceManager; import android.preference.PreferenceScreen; -import android.util.Log; import android.widget.Toast; import java.security.KeyStoreException; @@ -179,8 +178,6 @@ public class SettingsActivity extends XmppActivity implements } } } - } else if (name.equals("keep_foreground_service")) { - xmppConnectionService.toggleForegroundService(); } else if (resendPresence.contains(name)) { if (xmppConnectionServiceBound) { if (name.equals("away_when_screen_off") diff --git a/src/main/java/eu/siacs/conversations/ui/ShareLocationActivity.java b/src/main/java/eu/siacs/conversations/ui/ShareLocationActivity.java new file mode 100644 index 000000000..d2818d28a --- /dev/null +++ b/src/main/java/eu/siacs/conversations/ui/ShareLocationActivity.java @@ -0,0 +1,240 @@ +package eu.siacs.conversations.ui; + +import android.annotation.TargetApi; +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.location.Address; +import android.location.Geocoder; +import android.location.Location; +import android.os.AsyncTask; +import android.os.Build; +import android.os.Bundle; +import android.provider.Settings; +import android.text.TextUtils; +import android.util.Log; +import android.view.View; +import android.widget.Button; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import com.google.android.gms.common.ConnectionResult; +import com.google.android.gms.common.api.GoogleApiClient; +import com.google.android.gms.location.LocationListener; +import com.google.android.gms.location.LocationRequest; +import com.google.android.gms.location.LocationServices; +import com.google.android.gms.maps.CameraUpdateFactory; +import com.google.android.gms.maps.GoogleMap; +import com.google.android.gms.maps.MapFragment; +import com.google.android.gms.maps.OnMapReadyCallback; +import com.google.android.gms.maps.model.LatLng; + +import java.io.IOException; +import java.util.List; +import java.util.Locale; + +import eu.siacs.conversations.Config; +import eu.siacs.conversations.R; + +public class ShareLocationActivity extends Activity implements OnMapReadyCallback, + GoogleApiClient.ConnectionCallbacks, + GoogleApiClient.OnConnectionFailedListener, + LocationListener{ + + private GoogleMap mGoogleMap; + private GoogleApiClient mGoogleApiClient; + private LocationRequest mLocationRequest; + private Location mLastLocation; + private Button mCancelButton; + private Button mShareButton; + private RelativeLayout mSnackbar; + private RelativeLayout mLocationInfo; + private TextView mSnackbarLocation; + private TextView mSnackbarAction; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_share_locaction); + MapFragment fragment = (MapFragment) getFragmentManager().findFragmentById(R.id.map_fragment); + fragment.getMapAsync(this); + mGoogleApiClient = new GoogleApiClient.Builder(this) + .addApi(LocationServices.API) + .addConnectionCallbacks(this) + .addOnConnectionFailedListener(this) + .build(); + mCancelButton = (Button) findViewById(R.id.cancel_button); + mCancelButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + setResult(RESULT_CANCELED); + finish(); + } + }); + mShareButton = (Button) findViewById(R.id.share_button); + mShareButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if (mLastLocation != null) { + Intent result = new Intent(); + result.putExtra("latitude",mLastLocation.getLatitude()); + result.putExtra("longitude",mLastLocation.getLongitude()); + result.putExtra("altitude",mLastLocation.getAltitude()); + result.putExtra("accuracy",(int) mLastLocation.getAccuracy()); + setResult(RESULT_OK, result); + finish(); + } + } + }); + mSnackbar = (RelativeLayout) findViewById(R.id.snackbar); + mLocationInfo = (RelativeLayout) findViewById(R.id.snackbar_location); + mSnackbarLocation = (TextView) findViewById(R.id.snackbar_location_message); + mSnackbarAction = (TextView) findViewById(R.id.snackbar_action); + mSnackbarAction.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + startActivity(new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS)); + } + }); + } + + @Override + protected void onResume() { + super.onResume(); + this.mLastLocation = null; + if (isLocationEnabled()) { + this.mSnackbar.setVisibility(View.GONE); + } else { + this.mSnackbar.setVisibility(View.VISIBLE); + } + mShareButton.setEnabled(false); + mShareButton.setTextColor(0x8a000000); + mShareButton.setText(R.string.locating); + mGoogleApiClient.connect(); + } + + @Override + protected void onPause() { + mGoogleApiClient.disconnect(); + super.onPause(); + } + + @Override + public void onMapReady(GoogleMap googleMap) { + this.mGoogleMap = googleMap; + this.mGoogleMap.setMyLocationEnabled(true); + } + + private void centerOnLocation(LatLng location) { + this.mGoogleMap.animateCamera(CameraUpdateFactory.newLatLngZoom(location, Config.DEFAULT_ZOOM)); + } + + @Override + public void onConnected(Bundle bundle) { + mLocationRequest = LocationRequest.create(); + mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); + mLocationRequest.setInterval(1000); + + LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this); + } + + @Override + public void onConnectionSuspended(int i) { + + } + + @Override + public void onConnectionFailed(ConnectionResult connectionResult) { + + } + + @Override + public void onLocationChanged(Location location) { + double longitude = location.getLongitude(); + double latitude = location.getLatitude(); + + if (this.mLastLocation == null) { + centerOnLocation(new LatLng(location.getLatitude(), location.getLongitude())); + this.mShareButton.setEnabled(true); + this.mShareButton.setTextColor(0xde000000); + this.mShareButton.setText(R.string.share); + this.mLocationInfo.setVisibility(View.VISIBLE); + } + this.mLastLocation = location; + if (latitude != 0 && longitude != 0) { + Double[] lat_long = new Double[]{latitude, longitude}; + new ReverseGeocodingTask(getBaseContext()).execute(lat_long); + } + } + + @TargetApi(Build.VERSION_CODES.KITKAT) + private boolean isLocationEnabledKitkat() { + try { + int locationMode = Settings.Secure.getInt(getContentResolver(), Settings.Secure.LOCATION_MODE); + return locationMode != Settings.Secure.LOCATION_MODE_OFF; + } catch (Settings.SettingNotFoundException e) { + return false; + } + } + + @SuppressWarnings("deprecation") + private boolean isLocationEnabledLegacy() { + String locationProviders = Settings.Secure.getString(getContentResolver(), Settings.Secure.LOCATION_PROVIDERS_ALLOWED); + return !TextUtils.isEmpty(locationProviders); + } + + private boolean isLocationEnabled() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){ + return isLocationEnabledKitkat(); + }else{ + return isLocationEnabledLegacy(); + } + } + + private class ReverseGeocodingTask extends AsyncTask<Double, Void, String> { + Context mContext; + + public ReverseGeocodingTask(Context context){ + super(); + mContext = context; + } + + @Override + protected String doInBackground(Double... params) { + Geocoder geocoder = new Geocoder(mContext, Locale.getDefault()); + + double latitude = params[0].doubleValue(); + double longitude = params[1].doubleValue(); + + List<Address> addresses = null; + String address=""; + + try { + addresses = geocoder.getFromLocation(latitude, longitude,1); + } catch (IOException e) { + e.printStackTrace(); + } + + if (addresses != null) { + Address Address = addresses.get(0); + StringBuilder strAddress = new StringBuilder(""); + + for (int i = 0; i < Address.getMaxAddressLineIndex(); i++) { + strAddress.append(Address.getAddressLine(i)).append("\n"); + } + address = strAddress.toString(); + address = address.substring(0, address.length()-1); //trim last \n + } + + return address; + + } + + @Override + protected void onPostExecute(String address) { + // Setting address of the touched Position + mSnackbarLocation.setText(address); + Log.d(Config.LOGTAG,"Location: Address = "+ address); + } + } +} diff --git a/src/main/java/eu/siacs/conversations/ui/ShowFullscreenMessageActivity.java b/src/main/java/eu/siacs/conversations/ui/ShowFullscreenMessageActivity.java new file mode 100644 index 000000000..4cabf0bb2 --- /dev/null +++ b/src/main/java/eu/siacs/conversations/ui/ShowFullscreenMessageActivity.java @@ -0,0 +1,124 @@ +package eu.siacs.conversations.ui; + +import android.app.Activity; +import android.content.Intent; +import android.content.res.Configuration; +import android.graphics.Bitmap; +import android.net.Uri; +import android.os.Bundle; +import android.view.View; +import android.view.Window; +import android.view.WindowManager; +import android.widget.ImageView; +import android.widget.Toast; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.request.animation.GlideAnimation; +import com.bumptech.glide.request.target.BitmapImageViewTarget; +import com.github.rtoshiro.view.video.FullscreenVideoLayout; + +import java.io.File; +import java.io.IOException; + +import eu.siacs.conversations.R; +import uk.co.senab.photoview.PhotoView; +import uk.co.senab.photoview.PhotoViewAttacher; + +public class ShowFullscreenMessageActivity extends Activity { + + PhotoView mImage; + FullscreenVideoLayout mVideo; + ImageView mFullscreenbutton; + Uri mFileUri; + File mFile; + + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + WindowManager.LayoutParams layout = getWindow().getAttributes(); + layout.screenBrightness = 1; + getWindow().setAttributes(layout); + getWindow().requestFeature(Window.FEATURE_ACTION_BAR); + getWindow().addFlags(layout.FLAG_KEEP_SCREEN_ON); + getActionBar().hide(); + setContentView(R.layout.activity_fullscreen_message); + mImage = (PhotoView) findViewById(R.id.message_image_view); + mVideo = (FullscreenVideoLayout) findViewById(R.id.message_video_view); + mFullscreenbutton = (ImageView) findViewById(R.id.vcv_img_fullscreen); + } + + @Override + protected void onResume() { + super.onResume(); + Intent intent = getIntent(); + + if (intent != null) { + if (intent.hasExtra("image")) { + mFileUri = intent.getParcelableExtra("image"); + mFile = new File(mFileUri.getPath()); + if (mFileUri != null) { + DisplayImage(mFile); + } else { + Toast.makeText(ShowFullscreenMessageActivity.this, getString(R.string.file_deleted), Toast.LENGTH_SHORT).show(); + } + } else if (intent.hasExtra("video")) { + mFileUri = intent.getParcelableExtra("video"); + if (mFileUri != null) { + DisplayVideo(mFileUri); + } else { + Toast.makeText(ShowFullscreenMessageActivity.this, getString(R.string.file_deleted), Toast.LENGTH_SHORT).show(); + } + } + } + } + + @Override + protected void onPause() { + super.onPause(); + } + + private void DisplayImage(File file) { + final PhotoViewAttacher mAttacher = new PhotoViewAttacher(mImage); + mImage.setVisibility(View.VISIBLE); + try { + Glide.with(this) + .load(file) + .asBitmap() + .into(new BitmapImageViewTarget(mImage) { + @Override + public void onResourceReady(Bitmap resource, GlideAnimation<? super Bitmap> glideAnimation) { + super.onResourceReady(resource, glideAnimation); + mAttacher.update(); + } + }); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private void DisplayVideo(Uri uri) { + try { + mVideo.setVisibility(View.VISIBLE); + mVideo.setVideoURI(uri); + mFullscreenbutton.setVisibility(View.INVISIBLE); + mVideo.setShouldAutoplay(true); + + } catch (IOException e) { + e.printStackTrace(); + } + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + } + + public void onStop () { + WindowManager.LayoutParams layout = getWindow().getAttributes(); + layout.screenBrightness = -1; + getWindow().setAttributes(layout); + getWindow().clearFlags(layout.FLAG_KEEP_SCREEN_ON); + super.onStop(); + } +}
\ No newline at end of file diff --git a/src/main/java/eu/siacs/conversations/ui/ShowLocationActivity.java b/src/main/java/eu/siacs/conversations/ui/ShowLocationActivity.java new file mode 100644 index 000000000..0956be1a9 --- /dev/null +++ b/src/main/java/eu/siacs/conversations/ui/ShowLocationActivity.java @@ -0,0 +1,148 @@ +package eu.siacs.conversations.ui; + +import android.app.ActionBar; +import android.app.Activity; +import android.content.Intent; +import android.location.Address; +import android.location.Geocoder; +import android.os.Bundle; +import android.view.MenuItem; +import android.view.View; +import android.widget.TextView; + +import com.google.android.gms.maps.CameraUpdateFactory; +import com.google.android.gms.maps.GoogleMap; +import com.google.android.gms.maps.MapFragment; +import com.google.android.gms.maps.OnMapReadyCallback; +import com.google.android.gms.maps.model.LatLng; +import com.google.android.gms.maps.model.Marker; +import com.google.android.gms.maps.model.MarkerOptions; + +import java.util.List; +import java.util.Locale; + +import eu.siacs.conversations.Config; +import eu.siacs.conversations.R; + +public class ShowLocationActivity extends Activity implements OnMapReadyCallback { + + private GoogleMap mGoogleMap; + private LatLng mLocation; + private String mLocationName; + + class InfoWindowAdapter implements GoogleMap.InfoWindowAdapter { + + private final View InfoWindow; + + InfoWindowAdapter() { + InfoWindow = getLayoutInflater().inflate(R.layout.show_location_infowindow, null); + } + + @Override + public View getInfoWindow(Marker marker) { + return null; + } + + @Override + public View getInfoContents(Marker marker) { + + TextView Title = ((TextView) InfoWindow.findViewById(R.id.title)); + Title.setText(marker.getTitle()); + TextView Snippet = ((TextView) InfoWindow.findViewById(R.id.snippet)); + Snippet.setText(marker.getSnippet()); + + return InfoWindow; + } + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + ActionBar actionBar = getActionBar(); + if (actionBar != null) { + actionBar.setDisplayHomeAsUpEnabled(true); + } + + setContentView(R.layout.activity_show_locaction); + MapFragment fragment = (MapFragment) getFragmentManager().findFragmentById(R.id.map_fragment); + fragment.getMapAsync(this); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + finish(); + return true; + } + return super.onOptionsItemSelected(item); + } + + @Override + protected void onResume() { + super.onResume(); + Intent intent = getIntent(); + + this.mLocationName = intent != null ? intent.getStringExtra("name") : null; + + if (intent != null && intent.hasExtra("longitude") && intent.hasExtra("latitude")) { + double longitude = intent.getDoubleExtra("longitude",0); + double latitude = intent.getDoubleExtra("latitude",0); + this.mLocation = new LatLng(latitude,longitude); + if (this.mGoogleMap != null) { + markAndCenterOnLocation(this.mLocation, this.mLocationName); + } + } + } + + @Override + protected void onPause() { + super.onPause(); + } + + @Override + public void onMapReady(GoogleMap googleMap) { + this.mGoogleMap = googleMap; + this.mGoogleMap.setMyLocationEnabled(true); + if (this.mLocation != null) { + this.markAndCenterOnLocation(this.mLocation,this.mLocationName); + } + } + + private void markAndCenterOnLocation(LatLng location, String name) { + this.mGoogleMap.clear(); + MarkerOptions options = new MarkerOptions(); + options.position(location); + double longitude = mLocation.longitude; + double latitude = mLocation.latitude; + if (latitude != 0 && longitude != 0) { + Geocoder geoCoder = new Geocoder(getBaseContext(), Locale.getDefault()); + try { + List<Address> addresses = geoCoder.getFromLocation(latitude, longitude, 1); + + String address = ""; + if (addresses != null) { + Address Address = addresses.get(0); + StringBuilder strAddress = new StringBuilder(""); + + for (int i = 0; i < Address.getMaxAddressLineIndex(); i++) { + strAddress.append(Address.getAddressLine(i)).append("\n"); + } + address = strAddress.toString(); + address = address.substring(0, address.length()-1); //trim last \n + options.snippet(address); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + if (name != null) { + options.title(name); + } + this.mGoogleMap.setInfoWindowAdapter(new InfoWindowAdapter()); + this.mGoogleMap.addMarker(options).showInfoWindow(); + this.mGoogleMap.animateCamera(CameraUpdateFactory.newLatLngZoom(location, Config.DEFAULT_ZOOM)); + } + +} diff --git a/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java index 17f9944fd..3a515703f 100644 --- a/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/StartConversationActivity.java @@ -56,7 +56,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; -import java.util.concurrent.RunnableFuture; import java.util.concurrent.atomic.AtomicBoolean; import eu.siacs.conversations.Config; 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..e1e15452f --- /dev/null +++ b/src/main/java/eu/siacs/conversations/ui/UpdaterActivity.java @@ -0,0 +1,349 @@ +package eu.siacs.conversations.ui; + +import android.Manifest; +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.Build; +import android.os.Bundle; +import android.os.Environment; +import android.support.v4.app.ActivityCompat; +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 java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import eu.siacs.conversations.Config; +import eu.siacs.conversations.R; +import eu.siacs.conversations.persistance.DatabaseBackend; +import eu.siacs.conversations.services.UpdaterWebService; + +public class UpdaterActivity extends Activity { + + String appURI = ""; + private UpdateReceiver receiver = null; + private int versionCode = 0; + private DownloadManager downloadManager; + private long downloadReference; + //broadcast receiver to get notification about ongoing downloads + 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.getExtras().getLong(DownloadManager.EXTRA_DOWNLOAD_ID); + if (downloadReference == referenceId) { + File file = new File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "Conversations.apk"); + Log.d(Config.LOGTAG, "AppUpdater: Downloading of the new app version complete. Starting installation from " + file); + + //start the installation of the latest version + Intent installIntent = new Intent(Intent.ACTION_INSTALL_PACKAGE); + installIntent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive"); + installIntent.putExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, true); + installIntent.putExtra(Intent.EXTRA_RETURN_RESULT, true); + installIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + startActivity(installIntent); + + UpdaterActivity.this.finish(); + } + } + }; + + @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 (download complete) + registerReceiver(downloadReceiver, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE)); + + //check of internet is available before making a web service request + if (isNetworkAvailable(this)) { + Intent msgIntent = new Intent(this, UpdaterWebService.class); + msgIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + msgIntent.putExtra(UpdaterWebService.REQUEST_STRING, Config.UPDATE_URL); + + Toast.makeText(getApplicationContext(), + getText(R.string.checking_for_updates), + Toast.LENGTH_SHORT).show(); + startService(msgIntent); + } + } + + private void ExportDatabase() throws IOException { + + // Get hold of the db: + InputStream myInput = new FileInputStream(this.getDatabasePath(DatabaseBackend.DATABASE_NAME)); + + // Set the output folder on the SDcard + File directory = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/Pix-Art Messenger/.Database/"); + + // Create the folder if it doesn't exist: + if (!directory.exists()) { + directory.mkdirs(); + } + + // Set the output file stream up: + OutputStream myOutput = new FileOutputStream(directory.getPath() + "/Database.bak"); + + // Transfer bytes from the input file to the output file + byte[] buffer = new byte[1024]; + int length; + while ((length = myInput.read(buffer)) > 0) { + myOutput.write(buffer, 0, length); + } + + // Close and clear the streams + myOutput.flush(); + myOutput.close(); + myInput.close(); + } + + + @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; + } + + public boolean isStoragePermissionGranted() { + if (Build.VERSION.SDK_INT >= 23) { + if (checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE) + == PackageManager.PERMISSION_GRANTED) { + Log.d(Config.LOGTAG, "AppUpdater: Permission is granted"); + return true; + } else { + + Log.d(Config.LOGTAG, "AppUpdater: Permission is revoked"); + ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1); + return false; + } + } else { //permission is automatically granted on sdk<23 upon installation + Log.d(Config.LOGTAG, "AppUpdater: Permission is granted"); + return true; + } + } + + //show warning on back pressed + @Override + public void onBackPressed() { + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setMessage(R.string.cancel_update) + .setCancelable(false) + .setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + UpdaterActivity.this.finish(); + } + }) + .setNegativeButton(R.string.no, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + dialog.cancel(); + } + }); + AlertDialog alert = builder.create(); + alert.show(); + } + + //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 responseMessage = intent.getStringExtra(UpdaterWebService.RESPONSE_MESSAGE); + Log.d(Config.LOGTAG, "AppUpdater: Reponse: " + responseMessage); + + if (responseMessage == "" || responseMessage.isEmpty() || responseMessage == 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 response was successful check further + reponseObj = new JSONObject(responseMessage); + boolean success = reponseObj.getBoolean("success"); + if (success) { + //start backing up database + try { + ExportDatabase(); + Log.d(Config.LOGTAG,"AppUpdater: Database successfully exported"); + } catch (IOException e) { + e.printStackTrace(); + } + //Overall information about the contents of a package + //This corresponds 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 filesize = reponseObj.getString("filesize"); + //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, filesize, 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); + //ask for permissions on devices >= SDK 23 + if (isStoragePermissionGranted()) { + //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("Pix-Art Messenger Update"); + request.setDestinationInExternalFilesDir(UpdaterActivity.this, Environment.DIRECTORY_DOWNLOADS, "Conversations.apk"); + downloadReference = downloadManager.enqueue(request); + Toast.makeText(getApplicationContext(), + getText(R.string.download_started), + Toast.LENGTH_LONG).show(); + } + } + }) + .setNeutralButton(R.string.changelog, new DialogInterface.OnClickListener() { + //open link to changelog + public void onClick(DialogInterface dialog, int id) { + Uri uri = Uri.parse("https://github.com/kriztan/Conversations/blob/development/CHANGELOG.md"); // missing 'http://' will cause crashed + Intent intent = new Intent(Intent.ACTION_VIEW, uri); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + startActivity(intent); + //restart updater to show dialog again after coming back after opening changelog + recreate(); + } + }) + .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(); + } + } + + } + + } +} diff --git a/src/main/java/eu/siacs/conversations/ui/WelcomeActivity.java b/src/main/java/eu/siacs/conversations/ui/WelcomeActivity.java index 78f0f6094..3e35bd48c 100644 --- a/src/main/java/eu/siacs/conversations/ui/WelcomeActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/WelcomeActivity.java @@ -1,19 +1,68 @@ package eu.siacs.conversations.ui; import android.app.Activity; +import android.app.AlertDialog; +import android.content.DialogInterface; import android.content.Intent; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteException; +import android.net.Uri; import android.os.Bundle; +import android.os.Environment; +import android.util.Log; import android.view.View; import android.widget.Button; +import android.widget.TextView; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.List; + +import eu.siacs.conversations.Config; import eu.siacs.conversations.R; +import eu.siacs.conversations.persistance.DatabaseBackend; public class WelcomeActivity extends Activity { + boolean dbExist = checkDatabase(); + boolean backup_existing = false; + @Override protected void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.welcome); + + + //check if there is a backed up database -- + if (dbExist) { + backup_existing = true; + } + + final Button ImportDatabase = (Button) findViewById(R.id.import_database); + final TextView ImportText = (TextView) findViewById(R.id.import_text); + + if (backup_existing) { + ImportDatabase.setVisibility(View.VISIBLE); + ImportText.setVisibility(View.VISIBLE); + } + + ImportDatabase.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + try { + ImportDatabase(); + } catch (IOException e) { + e.printStackTrace(); + } + } + }); + final Button createAccount = (Button) findViewById(R.id.create_account); createAccount.setOnClickListener(new View.OnClickListener() { @Override @@ -23,7 +72,7 @@ public class WelcomeActivity extends Activity { startActivity(intent); } }); - final Button useOwnProvider = (Button) findViewById(R.id.use_own_provider); + final Button useOwnProvider = (Button) findViewById(R.id.use_existing_account); useOwnProvider.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { @@ -33,4 +82,98 @@ public class WelcomeActivity extends Activity { } + private boolean checkDatabase() { + + SQLiteDatabase checkDB = null; + String DB_PATH = Environment.getExternalStorageDirectory().getAbsolutePath() + "/Pix-Art Messenger/.Database/"; + String DB_NAME = "Database.bak"; + + try { + String myPath = DB_PATH + DB_NAME; + checkDB = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY); + Log.d(Config.LOGTAG,"Backup found"); + } catch (SQLiteException e) { + //database does't exist yet. + } + + if (checkDB != null) { + checkDB.close(); + } + return checkDB != null ? true : false; + } + + private void ImportDatabase() throws IOException { + + // Set location for the db: + OutputStream myOutput = new FileOutputStream(this.getDatabasePath(DatabaseBackend.DATABASE_NAME)); + + // Set the folder on the SDcard + File directory = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/Pix-Art Messenger/.Database/"); + + // Set the input file stream up: + InputStream myInput = new FileInputStream(directory.getPath() + "/Database.bak"); + + // Transfer bytes from the input file to the output file + byte[] buffer = new byte[1024]; + int length; + while ((length = myInput.read(buffer)) > 0) { + myOutput.write(buffer, 0, length); + } + Log.d(Config.LOGTAG,"Starting import of backup"); + + // Close and clear the streams + myOutput.flush(); + myOutput.close(); + myInput.close(); + + Log.d(Config.LOGTAG, "New Features - Uninstall old version of Pix-Art Messenger"); + if (isPackageInstalled("eu.siacs.conversations")) { + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setMessage(R.string.uninstall_app_text) + .setPositiveButton(R.string.uninstall, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialogInterface, int i) { + //start the deinstallation of old version + if (isPackageInstalled("eu.siacs.conversations")) { + Uri packageURI_VR = Uri.parse("package:eu.siacs.conversations"); + Intent uninstallIntent_VR = new Intent(Intent.ACTION_UNINSTALL_PACKAGE, packageURI_VR); + if (uninstallIntent_VR.resolveActivity(getPackageManager()) != null) { + startActivity(uninstallIntent_VR); + } + } + } + }) + .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialogInterface, int i) { + Log.d(Config.LOGTAG, "New Features - Uninstall cancled"); + restart(); + } + }); + builder.create().show(); + } else { + restart(); + } + + } + + private void restart() { + //restart app + Log.d(Config.LOGTAG, "Restarting " + getBaseContext().getPackageManager().getLaunchIntentForPackage(getBaseContext().getPackageName())); + Intent intent = getBaseContext().getPackageManager().getLaunchIntentForPackage(getBaseContext().getPackageName()); + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + startActivity(intent); + System.exit(0); + } + + private boolean isPackageInstalled(String targetPackage) { + List<ApplicationInfo> packages; + PackageManager pm; + pm = getPackageManager(); + packages = pm.getInstalledApplications(0); + for (ApplicationInfo packageInfo : packages) { + if (packageInfo.packageName.equals(targetPackage)) return true; + } + return false; + } + } diff --git a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java index 5dfa50832..ad1cbf905 100644 --- a/src/main/java/eu/siacs/conversations/ui/XmppActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/XmppActivity.java @@ -20,18 +20,15 @@ import android.content.ServiceConnection; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; -import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Color; import android.graphics.Point; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.Drawable; +import android.media.MediaMetadataRetriever; import android.net.Uri; import android.nfc.NdefMessage; import android.nfc.NdefRecord; import android.nfc.NfcAdapter; import android.nfc.NfcEvent; -import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; import android.os.Handler; @@ -52,6 +49,12 @@ import android.widget.LinearLayout; import android.widget.TextView; import android.widget.Toast; +import com.bumptech.glide.Glide; +import com.bumptech.glide.load.DecodeFormat; +import com.bumptech.glide.load.engine.DiskCacheStrategy; +import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; +import com.bumptech.glide.load.resource.bitmap.FileDescriptorBitmapDecoder; +import com.bumptech.glide.load.resource.bitmap.VideoBitmapDecoder; import com.google.zxing.BarcodeFormat; import com.google.zxing.EncodeHintType; import com.google.zxing.WriterException; @@ -61,12 +64,10 @@ import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; import net.java.otr4j.session.SessionID; -import java.io.FileNotFoundException; -import java.lang.ref.WeakReference; +import java.io.File; import java.util.ArrayList; import java.util.Hashtable; import java.util.List; -import java.util.concurrent.RejectedExecutionException; import eu.siacs.conversations.Config; import eu.siacs.conversations.R; @@ -358,11 +359,21 @@ public abstract class XmppActivity extends Activity { @Override public boolean onOptionsItemSelected(final MenuItem item) { switch (item.getItemId()) { + case R.id.action_invite_user: + inviteUser(); + break; 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)); + final Intent intent = new Intent(getApplicationContext(), EditAccountActivity.class); + Account mAccount = xmppConnectionService.getAccounts().get(0); + intent.putExtra("jid", mAccount.getJid().toBareJid().toString()); + intent.putExtra("init", false); + startActivity(intent); break; case android.R.id.home: finish(); @@ -384,7 +395,7 @@ public abstract class XmppActivity extends Activity { mTertiaryTextColor = getResources().getColor(R.color.black12); mColorRed = getResources().getColor(R.color.red800); mColorOrange = getResources().getColor(R.color.orange500); - mColorGreen = getResources().getColor(R.color.green500); + mColorGreen = getResources().getColor(R.color.realgreen); mPrimaryColor = getResources().getColor(R.color.primary); mPrimaryBackgroundColor = getResources().getColor(R.color.grey50); mSecondaryBackgroundColor = getResources().getColor(R.color.grey200); @@ -1054,7 +1065,7 @@ public abstract class XmppActivity extends Activity { } protected boolean manuallyChangePresence() { - return getPreferences().getBoolean("manually_change_presence", false); + return getPreferences().getBoolean("manually_change_presence", true); } protected void unregisterNdefPushMessageCallback() { @@ -1068,6 +1079,19 @@ public abstract class XmppActivity extends Activity { return null; } + private void inviteUser() { + Account mAccount = xmppConnectionService.getAccounts().get(0); + String user = mAccount.getJid().getLocalpart().toString(); + String domain = mAccount.getJid().getDomainpart().toString(); + String inviteURL = Config.inviteUserURL + user + "/" + domain; + String inviteText = getString(R.string.InviteText, user); + Intent intent = new Intent(android.content.Intent.ACTION_SEND); + intent.setType("text/plain"); + intent.putExtra(Intent.EXTRA_SUBJECT, user + " " + getString(R.string.inviteUser_Subject) + " " + getString(R.string.app_name)); + intent.putExtra(Intent.EXTRA_TEXT, inviteText + "\n\n" + inviteURL); + startActivity(Intent.createChooser(intent, getString(R.string.invite_contact))); + } + @Override public void onResume() { super.onResume(); @@ -1185,106 +1209,46 @@ public abstract class XmppActivity extends Activity { return xmppConnectionService.getAvatarService(); } - class BitmapWorkerTask extends AsyncTask<Message, Void, Bitmap> { - private final WeakReference<ImageView> imageViewReference; - private Message message = null; - - public BitmapWorkerTask(ImageView imageView) { - imageViewReference = new WeakReference<>(imageView); - } - - @Override - protected Bitmap doInBackground(Message... params) { - if (isCancelled()) { - return null; - } - message = params[0]; - try { - return xmppConnectionService.getFileBackend().getThumbnail( - message, (int) (metrics.density * 288), false); - } catch (FileNotFoundException e) { - return null; - } - } - - @Override - protected void onPostExecute(Bitmap bitmap) { - if (bitmap != null && !isCancelled()) { - final ImageView imageView = imageViewReference.get(); - if (imageView != null) { - imageView.setImageBitmap(bitmap); - imageView.setBackgroundColor(0x00000000); - } - } - } - } - - public void loadBitmap(Message message, ImageView imageView) { - Bitmap bm; - try { - bm = xmppConnectionService.getFileBackend().getThumbnail(message, - (int) (metrics.density * 288), true); - } catch (FileNotFoundException e) { - bm = null; - } - if (bm != null) { - cancelPotentialWork(message, imageView); - imageView.setImageBitmap(bm); - imageView.setBackgroundColor(0x00000000); - } else { - if (cancelPotentialWork(message, imageView)) { - imageView.setBackgroundColor(0xff333333); - imageView.setImageDrawable(null); - final BitmapWorkerTask task = new BitmapWorkerTask(imageView); - final AsyncDrawable asyncDrawable = new AsyncDrawable( - getResources(), null, task); - imageView.setImageDrawable(asyncDrawable); - try { - task.execute(message); - } catch (final RejectedExecutionException ignored) { - ignored.printStackTrace(); - } - } - } - } - - public static boolean cancelPotentialWork(Message message, ImageView imageView) { - final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView); - - if (bitmapWorkerTask != null) { - final Message oldMessage = bitmapWorkerTask.message; - if (oldMessage == null || message != oldMessage) { - bitmapWorkerTask.cancel(true); - } else { - return false; - } - } - return true; - } - - private static BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) { - if (imageView != null) { - final Drawable drawable = imageView.getDrawable(); - if (drawable instanceof AsyncDrawable) { - final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable; - return asyncDrawable.getBitmapWorkerTask(); - } - } - return null; - } - - static class AsyncDrawable extends BitmapDrawable { - private final WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference; - - public AsyncDrawable(Resources res, Bitmap bitmap, - BitmapWorkerTask bitmapWorkerTask) { - super(res, bitmap); - bitmapWorkerTaskReference = new WeakReference<>( - bitmapWorkerTask); - } - - public BitmapWorkerTask getBitmapWorkerTask() { - return bitmapWorkerTaskReference.get(); - } - } + public void loadBitmap(Message message, ImageView imageView) { + File bm; + bm = xmppConnectionService.getFileBackend().getFile(message, true); + try { + Glide.with(this) + .load(bm) + .override(400, 400) + .fitCenter() + //.centerCrop() + .diskCacheStrategy(DiskCacheStrategy.RESULT) + .into(imageView); + } catch (Exception e) { + e.printStackTrace(); + } + + } + + public void loadVideoPreview(Message message, ImageView imageView) { + File vp = xmppConnectionService.getFileBackend().getFile(message, true); + try { + MediaMetadataRetriever retriever = new MediaMetadataRetriever(); + //use one of overloaded setDataSource() functions to set your data source + retriever.setDataSource(this, Uri.fromFile(vp)); + String time = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION); + long microSecond = Long.parseLong(time); + int duration = (int) Math.ceil(microSecond / 2); //preview at half of video + BitmapPool bitmapPool = Glide.get(getApplicationContext()).getBitmapPool(); + VideoBitmapDecoder videoBitmapDecoder = new VideoBitmapDecoder(duration); + FileDescriptorBitmapDecoder fileDescriptorBitmapDecoder = new FileDescriptorBitmapDecoder(videoBitmapDecoder, bitmapPool, DecodeFormat.PREFER_ARGB_8888); + Glide.with(getApplicationContext()) + .load(vp) + .asBitmap() + .override(400, 400) + .fitCenter() + //.centerCrop() + .diskCacheStrategy(DiskCacheStrategy.RESULT) + .videoDecoder(fileDescriptorBitmapDecoder) + .into(imageView); + } catch (Exception e) { + e.printStackTrace(); + } + } } 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..393e3d100 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/AccountAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/AccountAdapter.java @@ -5,7 +5,6 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; -import android.widget.CompoundButton; import android.widget.ImageView; import android.widget.TextView; @@ -14,9 +13,7 @@ import java.util.List; import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.entities.Account; -import eu.siacs.conversations.ui.ManageAccountActivity; import eu.siacs.conversations.ui.XmppActivity; -import eu.siacs.conversations.ui.widget.Switch; public class AccountAdapter extends ArrayAdapter<Account> { @@ -43,7 +40,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: @@ -57,17 +54,6 @@ public class AccountAdapter extends ArrayAdapter<Account> { statusView.setTextColor(activity.getWarningTextColor()); break; } - final Switch tglAccountState = (Switch) view.findViewById(R.id.tgl_account_status); - final boolean isDisabled = (account.getStatus() == Account.State.DISABLED); - tglAccountState.setChecked(!isDisabled,false); - tglAccountState.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton compoundButton, boolean b) { - if (b == isDisabled && activity instanceof ManageAccountActivity) { - ((ManageAccountActivity) activity).onClickTglAccountState(account,b); - } - } - }); return view; } } diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java index 34c9d7b32..3625a371e 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java @@ -26,6 +26,7 @@ import eu.siacs.conversations.entities.Transferable; import eu.siacs.conversations.ui.ConversationActivity; import eu.siacs.conversations.ui.XmppActivity; import eu.siacs.conversations.utils.UIHelper; +import eu.siacs.conversations.xmpp.chatstate.ChatState; public class ConversationAdapter extends ArrayAdapter<Conversation> { @@ -37,108 +38,137 @@ public class ConversationAdapter extends ArrayAdapter<Conversation> { this.activity = activity; } + public static boolean cancelPotentialWork(Conversation conversation, ImageView imageView) { + final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView); + + if (bitmapWorkerTask != null) { + final Conversation oldConversation = bitmapWorkerTask.conversation; + if (oldConversation == null || conversation != oldConversation) { + bitmapWorkerTask.cancel(true); + } else { + return false; + } + } + return true; + } + + private static BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) { + if (imageView != null) { + final Drawable drawable = imageView.getDrawable(); + if (drawable instanceof AsyncDrawable) { + final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable; + return asyncDrawable.getBitmapWorkerTask(); + } + } + return null; + } + @Override public View getView(int position, View view, ViewGroup parent) { - if (view == null) { - LayoutInflater inflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - view = inflater.inflate(R.layout.conversation_list_row,parent, false); - } - Conversation conversation = getItem(position); - if (this.activity instanceof ConversationActivity) { - View swipeableItem = view.findViewById(R.id.swipeable_item); - ConversationActivity a = (ConversationActivity) this.activity; - int c = a.highlightSelectedConversations() && conversation == a.getSelectedConversation() ? a.getSecondaryBackgroundColor() : a.getPrimaryBackgroundColor(); - swipeableItem.setBackgroundColor(c); - } - TextView convName = (TextView) view.findViewById(R.id.conversation_name); - if (conversation.getMode() == Conversation.MODE_SINGLE || activity.useSubjectToIdentifyConference()) { - convName.setText(conversation.getName()); - } else { - convName.setText(conversation.getJid().toBareJid().toString()); - } - TextView mLastMessage = (TextView) view.findViewById(R.id.conversation_lastmsg); - TextView mTimestamp = (TextView) view.findViewById(R.id.conversation_lastupdate); - ImageView imagePreview = (ImageView) view.findViewById(R.id.conversation_lastimage); - ImageView notificationStatus = (ImageView) view.findViewById(R.id.notification_status); - - Message message = conversation.getLatestMessage(); - - if (!conversation.isRead()) { - convName.setTypeface(null, Typeface.BOLD); - } else { - convName.setTypeface(null, Typeface.NORMAL); - } - - if (message.getFileParams().width > 0 - && (message.getTransferable() == null - || message.getTransferable().getStatus() != Transferable.STATUS_DELETED)) { - mLastMessage.setVisibility(View.GONE); - imagePreview.setVisibility(View.VISIBLE); - activity.loadBitmap(message, imagePreview); - } else { - Pair<String,Boolean> preview = UIHelper.getMessagePreview(activity,message); - mLastMessage.setVisibility(View.VISIBLE); - imagePreview.setVisibility(View.GONE); - mLastMessage.setText(preview.first); - if (preview.second) { - if (conversation.isRead()) { - mLastMessage.setTypeface(null, Typeface.ITALIC); - } else { - mLastMessage.setTypeface(null,Typeface.BOLD_ITALIC); - } - } else { - if (conversation.isRead()) { - mLastMessage.setTypeface(null,Typeface.NORMAL); - } else { - mLastMessage.setTypeface(null,Typeface.BOLD); - } - } - } - - long muted_till = conversation.getLongAttribute(Conversation.ATTRIBUTE_MUTED_TILL,0); - if (muted_till == Long.MAX_VALUE) { - notificationStatus.setVisibility(View.VISIBLE); - notificationStatus.setImageResource(R.drawable.ic_notifications_off_grey600_24dp); - } else if (muted_till >= System.currentTimeMillis()) { - notificationStatus.setVisibility(View.VISIBLE); - notificationStatus.setImageResource(R.drawable.ic_notifications_paused_grey600_24dp); - } else if (conversation.alwaysNotify()) { - notificationStatus.setVisibility(View.GONE); - } else { - notificationStatus.setVisibility(View.VISIBLE); - notificationStatus.setImageResource(R.drawable.ic_notifications_none_grey600_24dp); - } - - mTimestamp.setText(UIHelper.readableTimeDifference(activity,conversation.getLatestMessage().getTimeSent())); - ImageView profilePicture = (ImageView) view.findViewById(R.id.conversation_image); - loadAvatar(conversation,profilePicture); - - return view; - } - - class BitmapWorkerTask extends AsyncTask<Conversation, Void, Bitmap> { - private final WeakReference<ImageView> imageViewReference; - private Conversation conversation = null; - - public BitmapWorkerTask(ImageView imageView) { - imageViewReference = new WeakReference<>(imageView); - } - - @Override - protected Bitmap doInBackground(Conversation... params) { - return activity.avatarService().get(params[0], activity.getPixel(56), isCancelled()); - } - - @Override - protected void onPostExecute(Bitmap bitmap) { - if (bitmap != null && !isCancelled()) { - final ImageView imageView = imageViewReference.get(); - if (imageView != null) { - imageView.setImageBitmap(bitmap); - imageView.setBackgroundColor(0x00000000); - } - } - } + if (view == null) { + LayoutInflater inflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + view = inflater.inflate(R.layout.conversation_list_row, parent, false); + } + Conversation conversation = getItem(position); + if (this.activity instanceof ConversationActivity) { + View swipeableItem = view.findViewById(R.id.swipeable_item); + ConversationActivity a = (ConversationActivity) this.activity; + int c = a.highlightSelectedConversations() && conversation == a.getSelectedConversation() ? a.getSecondaryBackgroundColor() : a.getPrimaryBackgroundColor(); + swipeableItem.setBackgroundColor(c); + } + TextView convName = (TextView) view.findViewById(R.id.conversation_name); + if (conversation.getMode() == Conversation.MODE_SINGLE || activity.useSubjectToIdentifyConference()) { + convName.setText(conversation.getName()); + } else { + convName.setText(conversation.getJid().toBareJid().toString()); + } + TextView mLastMessage = (TextView) view.findViewById(R.id.conversation_lastmsg); + TextView mTimestamp = (TextView) view.findViewById(R.id.conversation_lastupdate); + ImageView imagePreview = (ImageView) view.findViewById(R.id.conversation_lastimage); + ImageView notificationStatus = (ImageView) view.findViewById(R.id.notification_status); + + Message message = conversation.getLatestMessage(); + String mimeType = message.getMimeType(); + + if (!conversation.isRead()) { + convName.setTypeface(null, Typeface.BOLD); + } else { + convName.setTypeface(null, Typeface.NORMAL); + } + + + if ((message.getTransferable() == null + || message.getTransferable().getStatus() != Transferable.STATUS_DELETED)) { + if (mimeType != null && message.getMimeType().startsWith("video/")) { + mLastMessage.setVisibility(View.GONE); + imagePreview.setVisibility(View.VISIBLE); + activity.loadVideoPreview(message, imagePreview); + } else if (message.getFileParams().width > 0) { + mLastMessage.setVisibility(View.GONE); + imagePreview.setVisibility(View.VISIBLE); + activity.loadBitmap(message, imagePreview); + } else { + Pair<String, Boolean> preview = UIHelper.getMessagePreview(activity, message); + mLastMessage.setVisibility(View.VISIBLE); + imagePreview.setVisibility(View.GONE); + mLastMessage.setText(preview.first); + if (preview.second) { + if (conversation.isRead()) { + mLastMessage.setTypeface(null, Typeface.ITALIC); + } else { + mLastMessage.setTypeface(null, Typeface.BOLD_ITALIC); + } + } else { + if (conversation.isRead()) { + mLastMessage.setTypeface(null, Typeface.NORMAL); + } else { + mLastMessage.setTypeface(null, Typeface.BOLD); + } + } + } + } else { + Pair<String, Boolean> preview = UIHelper.getMessagePreview(activity, message); + mLastMessage.setVisibility(View.VISIBLE); + imagePreview.setVisibility(View.GONE); + mLastMessage.setText(preview.first); + if (preview.second) { + if (conversation.isRead()) { + mLastMessage.setTypeface(null, Typeface.ITALIC); + } else { + mLastMessage.setTypeface(null, Typeface.BOLD_ITALIC); + } + } else { + if (conversation.isRead()) { + mLastMessage.setTypeface(null, Typeface.NORMAL); + } else { + mLastMessage.setTypeface(null, Typeface.BOLD); + } + } + } + + long muted_till = conversation.getLongAttribute(Conversation.ATTRIBUTE_MUTED_TILL, 0); + if (muted_till == Long.MAX_VALUE) { + notificationStatus.setVisibility(View.VISIBLE); + notificationStatus.setImageResource(R.drawable.ic_notifications_off_grey600_24dp); + } else if (muted_till >= System.currentTimeMillis()) { + notificationStatus.setVisibility(View.VISIBLE); + notificationStatus.setImageResource(R.drawable.ic_notifications_paused_grey600_24dp); + } else if (conversation.alwaysNotify()) { + notificationStatus.setVisibility(View.GONE); + } else { + notificationStatus.setVisibility(View.VISIBLE); + notificationStatus.setImageResource(R.drawable.ic_notifications_none_grey600_24dp); + } + + mTimestamp.setText(UIHelper.readableTimeDifference(activity, conversation.getLatestMessage().getTimeSent())); + ImageView profilePicture = (ImageView) view.findViewById(R.id.conversation_image); + loadAvatar(conversation, profilePicture); + + if (conversation.getIncomingChatState().equals(ChatState.COMPOSING)) { + mLastMessage.setText(R.string.is_typing); + mLastMessage.setTypeface(null, Typeface.BOLD_ITALIC); + } + return view; } public void loadAvatar(Conversation conversation, ImageView imageView) { @@ -162,31 +192,6 @@ public class ConversationAdapter extends ArrayAdapter<Conversation> { } } - public static boolean cancelPotentialWork(Conversation conversation, ImageView imageView) { - final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView); - - if (bitmapWorkerTask != null) { - final Conversation oldConversation = bitmapWorkerTask.conversation; - if (oldConversation == null || conversation != oldConversation) { - bitmapWorkerTask.cancel(true); - } else { - return false; - } - } - return true; - } - - private static BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) { - if (imageView != null) { - final Drawable drawable = imageView.getDrawable(); - if (drawable instanceof AsyncDrawable) { - final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable; - return asyncDrawable.getBitmapWorkerTask(); - } - } - return null; - } - static class AsyncDrawable extends BitmapDrawable { private final WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference; @@ -199,4 +204,29 @@ public class ConversationAdapter extends ArrayAdapter<Conversation> { return bitmapWorkerTaskReference.get(); } } + + class BitmapWorkerTask extends AsyncTask<Conversation, Void, Bitmap> { + private final WeakReference<ImageView> imageViewReference; + private Conversation conversation = null; + + public BitmapWorkerTask(ImageView imageView) { + imageViewReference = new WeakReference<>(imageView); + } + + @Override + protected Bitmap doInBackground(Conversation... params) { + return activity.avatarService().get(params[0], activity.getPixel(56)); + } + + @Override + protected void onPostExecute(Bitmap bitmap) { + if (bitmap != null) { + final ImageView imageView = imageViewReference.get(); + if (imageView != null) { + imageView.setImageBitmap(bitmap); + imageView.setBackgroundColor(0x00000000); + } + } + } + } }
\ No newline at end of file diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/ListItemAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/ListItemAdapter.java index c29b01bcf..bc2263ba9 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/ListItemAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/ListItemAdapter.java @@ -24,7 +24,6 @@ import eu.siacs.conversations.R; import eu.siacs.conversations.entities.ListItem; import eu.siacs.conversations.ui.XmppActivity; import eu.siacs.conversations.utils.UIHelper; -import eu.siacs.conversations.xmpp.jid.Jid; public class ListItemAdapter extends ArrayAdapter<ListItem> { 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 5ba29802d..a2e440628 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java @@ -1,6 +1,7 @@ package eu.siacs.conversations.ui.adapter; import android.content.ActivityNotFoundException; +import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; @@ -20,6 +21,7 @@ import android.text.style.StyleSpan; import android.text.util.Linkify; import android.util.DisplayMetrics; import android.util.Patterns; +import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.View.OnLongClickListener; @@ -28,11 +30,13 @@ import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.ImageView; import android.widget.LinearLayout; +import android.widget.RelativeLayout; import android.widget.TextView; import android.widget.Toast; import java.lang.ref.WeakReference; import java.net.URL; +import java.util.HashMap; import java.util.List; import java.util.concurrent.RejectedExecutionException; import java.util.regex.MatchResult; @@ -49,9 +53,11 @@ import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.entities.Message.FileParams; import eu.siacs.conversations.entities.Transferable; import eu.siacs.conversations.ui.ConversationActivity; +import eu.siacs.conversations.ui.ShowFullscreenMessageActivity; import eu.siacs.conversations.utils.CryptoHelper; import eu.siacs.conversations.utils.GeoHelper; import eu.siacs.conversations.utils.UIHelper; +import nl.changer.audiowife.AudioWife; public class MessageAdapter extends ArrayAdapter<Message> { @@ -80,6 +86,7 @@ public class MessageAdapter extends ArrayAdapter<Message> { } }; private boolean mIndicateReceived = false; + private HashMap<Integer, AudioWife> audioPlayer; private boolean mUseWhiteBackground = false; public MessageAdapter(ConversationActivity activity, List<Message> messages) { @@ -115,14 +122,14 @@ public class MessageAdapter extends ArrayAdapter<Message> { @Override public int getItemViewType(int position) { - return this.getItemViewType(getItem(position)); + return getItemViewType(getItem(position)); } private int getMessageTextColor(boolean onDark, boolean primary) { if (onDark) { - return activity.getResources().getColor(primary ? R.color.white : R.color.white70); + return activity.getResources().getColor(primary ? R.color.dark : R.color.primary); } else { - return activity.getResources().getColor(primary ? R.color.black87 : R.color.black54); + return activity.getResources().getColor(primary ? R.color.dark : R.color.primary); } } @@ -132,13 +139,12 @@ public class MessageAdapter extends ArrayAdapter<Message> { boolean error = false; if (viewHolder.indicatorReceived != null) { viewHolder.indicatorReceived.setVisibility(View.GONE); + viewHolder.indicatorRead.setVisibility(View.GONE); } if (viewHolder.edit_indicator != null) { if (message.edited()) { viewHolder.edit_indicator.setVisibility(View.VISIBLE); - viewHolder.edit_indicator.setImageResource(darkBackground ? R.drawable.ic_mode_edit_white_18dp : R.drawable.ic_mode_edit_black_18dp); - viewHolder.edit_indicator.setAlpha(darkBackground ? 0.7f : 0.57f); } else { viewHolder.edit_indicator.setVisibility(View.GONE); } @@ -179,6 +185,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: @@ -199,7 +206,6 @@ public class MessageAdapter extends ArrayAdapter<Message> { if (message.getEncryption() == Message.ENCRYPTION_NONE) { viewHolder.indicator.setVisibility(View.GONE); } else { - viewHolder.indicator.setImageResource(darkBackground ? R.drawable.ic_lock_white_18dp : R.drawable.ic_lock_black_18dp); viewHolder.indicator.setVisibility(View.VISIBLE); if (message.getEncryption() == Message.ENCRYPTION_AXOLOTL) { XmppAxolotlSession.Trust trust = message.getConversation() @@ -257,6 +263,7 @@ public class MessageAdapter extends ArrayAdapter<Message> { } private void displayInfoMessage(ViewHolder viewHolder, String text, boolean darkBackground) { + viewHolder.aw_player.setVisibility(View.GONE); if (viewHolder.download_button != null) { viewHolder.download_button.setVisibility(View.GONE); } @@ -269,6 +276,7 @@ public class MessageAdapter extends ArrayAdapter<Message> { } private void displayDecryptionFailed(ViewHolder viewHolder, boolean darkBackground) { + viewHolder.aw_player.setVisibility(View.GONE); if (viewHolder.download_button != null) { viewHolder.download_button.setVisibility(View.GONE); } @@ -282,6 +290,7 @@ public class MessageAdapter extends ArrayAdapter<Message> { } private void displayHeartMessage(final ViewHolder viewHolder, final String body) { + viewHolder.aw_player.setVisibility(View.GONE); if (viewHolder.download_button != null) { viewHolder.download_button.setVisibility(View.GONE); } @@ -395,6 +404,7 @@ public class MessageAdapter extends ArrayAdapter<Message> { private void displayDownloadableMessage(ViewHolder viewHolder, final Message message, String text) { + viewHolder.aw_player.setVisibility(View.GONE); viewHolder.image.setVisibility(View.GONE); viewHolder.messageBody.setVisibility(View.GONE); viewHolder.download_button.setVisibility(View.VISIBLE); @@ -409,7 +419,31 @@ public class MessageAdapter extends ArrayAdapter<Message> { viewHolder.download_button.setOnLongClickListener(openContextMenu); } + private void displayAudioMessage(ViewHolder viewHolder, final Message message, int position) { + if (audioPlayer == null) audioPlayer = new HashMap<>(); + viewHolder.image.setVisibility(View.GONE); + viewHolder.messageBody.setVisibility(View.GONE); + if (viewHolder.download_button != null) viewHolder.download_button.setVisibility(View.GONE); + viewHolder.aw_player.setVisibility(View.VISIBLE); + Uri audioFile = Uri.fromFile(activity.xmppConnectionService.getFileBackend().getFile(message)); + + AudioWife audioWife = audioPlayer.get(position); + if (audioWife == null) { + audioWife = new AudioWife(); + audioWife.init(getContext(), audioFile); + audioPlayer.put(position, audioWife); + RelativeLayout vg = new RelativeLayout(activity); + LayoutInflater layoutInflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); + audioWife.useDefaultUi(vg, layoutInflater); + viewHolder.aw_player.addView(audioWife.getPlayerUi()); + } else { + audioWife.cleanPlayerUi(); + viewHolder.aw_player.addView(audioWife.getPlayerUi()); + } + } + private void displayOpenableMessage(ViewHolder viewHolder,final Message message) { + viewHolder.aw_player.setVisibility(View.GONE); viewHolder.image.setVisibility(View.GONE); viewHolder.messageBody.setVisibility(View.GONE); viewHolder.download_button.setVisibility(View.VISIBLE); @@ -425,6 +459,7 @@ public class MessageAdapter extends ArrayAdapter<Message> { } private void displayLocationMessage(ViewHolder viewHolder, final Message message) { + viewHolder.aw_player.setVisibility(View.GONE); viewHolder.image.setVisibility(View.GONE); viewHolder.messageBody.setVisibility(View.GONE); viewHolder.download_button.setVisibility(View.VISIBLE); @@ -441,13 +476,14 @@ public class MessageAdapter extends ArrayAdapter<Message> { private void displayImageMessage(ViewHolder viewHolder, final Message message) { + viewHolder.aw_player.setVisibility(View.GONE); if (viewHolder.download_button != null) { viewHolder.download_button.setVisibility(View.GONE); } 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) { @@ -471,6 +507,25 @@ public class MessageAdapter extends ArrayAdapter<Message> { viewHolder.image.setOnLongClickListener(openContextMenu); } + private void displayVideoMessage(ViewHolder viewHolder, + final Message message) { + viewHolder.aw_player.setVisibility(View.GONE); + if (viewHolder.download_button != null) { + viewHolder.download_button.setVisibility(View.GONE); + } + viewHolder.messageBody.setVisibility(View.GONE); + viewHolder.image.setVisibility(View.VISIBLE); + activity.loadVideoPreview(message, viewHolder.image); + viewHolder.image.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + openDownloadable(message); + } + }); + viewHolder.image.setOnLongClickListener(openContextMenu); + } + private void loadMoreMessages(Conversation conversation) { conversation.setLastClearHistory(0); conversation.setHasMessagesLeftOnServer(true); @@ -485,78 +540,81 @@ public class MessageAdapter extends ArrayAdapter<Message> { } @Override - public View getView(int position, View view, ViewGroup parent) { + public View getView(int position, View unused, ViewGroup parent) { final Message message = getItem(position); final boolean isInValidSession = message.isValidInSession(); final Conversation conversation = message.getConversation(); final Account account = conversation.getAccount(); final int type = getItemViewType(position); - ViewHolder viewHolder; - if (view == null) { - viewHolder = new ViewHolder(); - switch (type) { - case SENT: - view = activity.getLayoutInflater().inflate( - R.layout.message_sent, parent, false); - viewHolder.message_box = (LinearLayout) view - .findViewById(R.id.message_box); - viewHolder.contact_picture = (ImageView) view - .findViewById(R.id.message_photo); - viewHolder.download_button = (Button) view - .findViewById(R.id.download_button); - viewHolder.indicator = (ImageView) view - .findViewById(R.id.security_indicator); - viewHolder.edit_indicator = (ImageView) view.findViewById(R.id.edit_indicator); - viewHolder.image = (ImageView) view - .findViewById(R.id.message_image); - viewHolder.messageBody = (TextView) view - .findViewById(R.id.message_body); - viewHolder.time = (TextView) view - .findViewById(R.id.message_time); - viewHolder.indicatorReceived = (ImageView) view - .findViewById(R.id.indicator_received); - break; - case RECEIVED: - view = activity.getLayoutInflater().inflate( - R.layout.message_received, parent, false); - viewHolder.message_box = (LinearLayout) view - .findViewById(R.id.message_box); - viewHolder.contact_picture = (ImageView) view - .findViewById(R.id.message_photo); - viewHolder.download_button = (Button) view - .findViewById(R.id.download_button); - viewHolder.indicator = (ImageView) view - .findViewById(R.id.security_indicator); - viewHolder.edit_indicator = (ImageView) view.findViewById(R.id.edit_indicator); - viewHolder.image = (ImageView) view - .findViewById(R.id.message_image); - viewHolder.messageBody = (TextView) view - .findViewById(R.id.message_body); - viewHolder.time = (TextView) view - .findViewById(R.id.message_time); - viewHolder.indicatorReceived = (ImageView) view - .findViewById(R.id.indicator_received); - viewHolder.encryption = (TextView) view.findViewById(R.id.message_encryption); - break; - case STATUS: - view = activity.getLayoutInflater().inflate(R.layout.message_status, parent, false); - viewHolder.contact_picture = (ImageView) view.findViewById(R.id.message_photo); - viewHolder.status_message = (TextView) view.findViewById(R.id.status_message); - viewHolder.load_more_messages = (Button) view.findViewById(R.id.load_more_messages); - break; - default: - viewHolder = null; - break; - } - view.setTag(viewHolder); - } else { - viewHolder = (ViewHolder) view.getTag(); - if (viewHolder == null) { - return view; - } - } - - boolean darkBackground = (type == RECEIVED && (!isInValidSession || !mUseWhiteBackground)); + ViewHolder viewHolder; + View view; + viewHolder = new ViewHolder(); + switch (type) { + case SENT: + view = activity.getLayoutInflater().inflate( + R.layout.message_sent, parent, false); + viewHolder.message_box = (LinearLayout) view + .findViewById(R.id.message_box); + viewHolder.contact_picture = (ImageView) view + .findViewById(R.id.message_photo); + viewHolder.aw_player = (ViewGroup) view.findViewById(R.id.aw_player); + viewHolder.download_button = (Button) view + .findViewById(R.id.download_button); + viewHolder.indicator = (ImageView) view + .findViewById(R.id.security_indicator); + viewHolder.edit_indicator = (ImageView) view.findViewById(R.id.edit_indicator); + viewHolder.image = (ImageView) view + .findViewById(R.id.message_image); + viewHolder.messageBody = (TextView) view + .findViewById(R.id.message_body); + viewHolder.time = (TextView) view + .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( + R.layout.message_received, parent, false); + viewHolder.message_box = (LinearLayout) view + .findViewById(R.id.message_box); + viewHolder.contact_picture = (ImageView) view + .findViewById(R.id.message_photo); + viewHolder.aw_player = (ViewGroup) view.findViewById(R.id.aw_player); + viewHolder.download_button = (Button) view + .findViewById(R.id.download_button); + viewHolder.indicator = (ImageView) view + .findViewById(R.id.security_indicator); + viewHolder.edit_indicator = (ImageView) view.findViewById(R.id.edit_indicator); + viewHolder.image = (ImageView) view + .findViewById(R.id.message_image); + viewHolder.messageBody = (TextView) view + .findViewById(R.id.message_body); + viewHolder.time = (TextView) view + .findViewById(R.id.message_time); + viewHolder.indicatorReceived = (ImageView) view + .findViewById(R.id.indicator_received); + viewHolder.encryption = (TextView) view.findViewById(R.id.message_encryption); + break; + case STATUS: + view = activity.getLayoutInflater().inflate(R.layout.message_status, parent, false); + viewHolder.contact_picture = (ImageView) view.findViewById(R.id.message_photo); + viewHolder.status_message = (TextView) view.findViewById(R.id.status_message); + viewHolder.load_more_messages = (Button) view.findViewById(R.id.load_more_messages); + break; + default: + view = new View(getContext()); + viewHolder = null; + break; + } + view.setTag(viewHolder); + if (viewHolder == null) { + return view; + } + + + boolean darkBackground = (type == SENT && (!isInValidSession || !mUseWhiteBackground)); if (type == STATUS) { if ("LOAD_MORE".equals(message.getBody())) { @@ -614,6 +672,7 @@ public class MessageAdapter extends ArrayAdapter<Message> { }); final Transferable transferable = message.getTransferable(); + String mimeType = message.getMimeType(); if (transferable != null && transferable.getStatus() != Transferable.STATUS_UPLOADING) { if (transferable.getStatus() == Transferable.STATUS_OFFER) { displayDownloadableMessage(viewHolder,message,activity.getString(R.string.download_x_file, UIHelper.getFileDescriptionString(activity, message))); @@ -628,7 +687,15 @@ public class MessageAdapter extends ArrayAdapter<Message> { if (message.getFileParams().width > 0) { displayImageMessage(viewHolder,message); } else { - displayOpenableMessage(viewHolder, message); + if (mimeType != null) { + if (message.getMimeType().startsWith("audio/")) { + displayAudioMessage(viewHolder, message, position); + } else if (message.getMimeType().startsWith("video/")) { + displayVideoMessage(viewHolder, message); + //ToDo add overlay e.g. play button + } + else displayOpenableMessage(viewHolder, message); + } else displayOpenableMessage(viewHolder, message); } } else if (message.getEncryption() == Message.ENCRYPTION_PGP) { if (activity.hasPgp()) { @@ -657,7 +724,8 @@ public class MessageAdapter extends ArrayAdapter<Message> { displayLocationMessage(viewHolder,message); } else if (message.bodyIsHeart()) { displayHeartMessage(viewHolder, message.getBody().trim()); - } else if (message.treatAsDownloadable() == Message.Decision.MUST) { + } else if (message.treatAsDownloadable() == Message.Decision.MUST || + message.treatAsDownloadable() == Message.Decision.SHOULD) { try { URL url = new URL(message.getBody()); displayDownloadableMessage(viewHolder, @@ -678,11 +746,7 @@ public class MessageAdapter extends ArrayAdapter<Message> { if (type == RECEIVED) { if(isInValidSession) { - if (mUseWhiteBackground) { - viewHolder.message_box.setBackgroundResource(R.drawable.message_bubble_received_white); - } else { - viewHolder.message_box.setBackgroundResource(R.drawable.message_bubble_received); - } + viewHolder.message_box.setBackgroundResource(R.drawable.message_bubble_received); viewHolder.encryption.setVisibility(View.GONE); } else { viewHolder.message_box.setBackgroundResource(R.drawable.message_bubble_received_warning); @@ -691,36 +755,65 @@ public class MessageAdapter extends ArrayAdapter<Message> { } } + if (type == SENT) { + if (mUseWhiteBackground) { + viewHolder.message_box.setBackgroundResource(R.drawable.message_bubble_sent_white); + } else { + viewHolder.message_box.setBackgroundResource(R.drawable.message_bubble_sent); + } + } + displayStatus(viewHolder, message, type, darkBackground); return view; } - public void openDownloadable(Message message) { - DownloadableFile file = activity.xmppConnectionService.getFileBackend().getFile(message); - if (!file.exists()) { - Toast.makeText(activity,R.string.file_deleted,Toast.LENGTH_SHORT).show(); - return; - } - Intent openIntent = new Intent(Intent.ACTION_VIEW); - String mime = file.getMimeType(); - if (mime == null) { - mime = "*/*"; - } - openIntent.setDataAndType(Uri.fromFile(file), mime); - PackageManager manager = activity.getPackageManager(); - List<ResolveInfo> infos = manager.queryIntentActivities(openIntent, 0); - if (infos.size() == 0) { - openIntent.setDataAndType(Uri.fromFile(file),"*/*"); - } - try { - getContext().startActivity(openIntent); - return; - } catch (ActivityNotFoundException e) { - //ignored - } - Toast.makeText(activity,R.string.no_application_found_to_open_file,Toast.LENGTH_SHORT).show(); - } + public void openDownloadable(Message message) { + DownloadableFile file = activity.xmppConnectionService.getFileBackend().getFile(message); + if (!file.exists()) { + Toast.makeText(activity, R.string.file_deleted, Toast.LENGTH_SHORT).show(); + return; + } + String mime = file.getMimeType(); + + if (mime.startsWith("image/")) { + Intent intent = new Intent(getContext(), ShowFullscreenMessageActivity.class); + intent.putExtra("image", Uri.fromFile(file)); + try { + activity.startActivity(intent); + return; + } catch (ActivityNotFoundException e) { + //ignored + } + } else if (mime.startsWith("video/")) { + Intent intent = new Intent(getContext(), ShowFullscreenMessageActivity.class); + intent.putExtra("video", Uri.fromFile(file)); + try { + activity.startActivity(intent); + return; + } catch (ActivityNotFoundException e) { + //ignored + } + } + Intent openIntent = new Intent(Intent.ACTION_VIEW); + if (mime == null) { + mime = "*/*"; + } + openIntent.setDataAndType(Uri.fromFile(file), mime); + PackageManager manager = activity.getPackageManager(); + List<ResolveInfo> infos = manager.queryIntentActivities(openIntent, 0); + if (infos.size() == 0) { + openIntent.setDataAndType(Uri.fromFile(file), "*/*"); + } + try { + getContext().startActivity(openIntent); + return; + } catch (ActivityNotFoundException e) { + //ignored + } + Toast.makeText(activity, R.string.no_application_found_to_open_file, Toast.LENGTH_SHORT).show(); + + } public void showLocation(Message message) { for(Intent intent : GeoHelper.createGeoIntentsFromMessage(message)) { @@ -749,9 +842,11 @@ public class MessageAdapter extends ArrayAdapter<Message> { protected LinearLayout message_box; protected Button download_button; + protected ViewGroup aw_player; 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/ui/forms/FormFieldWrapper.java b/src/main/java/eu/siacs/conversations/ui/forms/FormFieldWrapper.java index 3a21ade3b..3b051191b 100644 --- a/src/main/java/eu/siacs/conversations/ui/forms/FormFieldWrapper.java +++ b/src/main/java/eu/siacs/conversations/ui/forms/FormFieldWrapper.java @@ -4,13 +4,11 @@ import android.content.Context; import android.text.SpannableString; import android.text.style.ForegroundColorSpan; import android.text.style.StyleSpan; -import android.util.Log; import android.view.LayoutInflater; import android.view.View; import java.util.List; -import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.xmpp.forms.Field; diff --git a/src/main/java/eu/siacs/conversations/utils/DNSHelper.java b/src/main/java/eu/siacs/conversations/utils/DNSHelper.java index ac64cf2e8..b51a9f16a 100644 --- a/src/main/java/eu/siacs/conversations/utils/DNSHelper.java +++ b/src/main/java/eu/siacs/conversations/utils/DNSHelper.java @@ -19,9 +19,9 @@ import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.Random; import java.util.TreeMap; -import java.util.Map; import java.util.regex.Pattern; import de.measite.minidns.Client; diff --git a/src/main/java/eu/siacs/conversations/utils/ExceptionHandler.java b/src/main/java/eu/siacs/conversations/utils/ExceptionHandler.java index efc83bcb2..b8a0fa511 100644 --- a/src/main/java/eu/siacs/conversations/utils/ExceptionHandler.java +++ b/src/main/java/eu/siacs/conversations/utils/ExceptionHandler.java @@ -2,9 +2,6 @@ package eu.siacs.conversations.utils; import android.content.Context; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.OutputStream; import java.io.PrintWriter; import java.io.StringWriter; import java.io.Writer; diff --git a/src/main/java/eu/siacs/conversations/utils/ExceptionHelper.java b/src/main/java/eu/siacs/conversations/utils/ExceptionHelper.java index 962613fb6..79c547889 100644 --- a/src/main/java/eu/siacs/conversations/utils/ExceptionHelper.java +++ b/src/main/java/eu/siacs/conversations/utils/ExceptionHelper.java @@ -7,15 +7,12 @@ import android.content.DialogInterface.OnClickListener; import android.content.SharedPreferences; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; -import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.Signature; import android.preference.PreferenceManager; -import android.text.format.DateUtils; import android.util.Log; import java.io.BufferedReader; import java.io.FileInputStream; -import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStream; @@ -46,8 +43,8 @@ public class ExceptionHelper { try { final SharedPreferences preferences = PreferenceManager .getDefaultSharedPreferences(activity); - boolean neverSend = preferences.getBoolean("never_send", false); - if (neverSend || Config.BUG_REPORTS == null) { + boolean crashreport = preferences.getBoolean("crashreport", true); + if (!crashreport || Config.BUG_REPORTS == null) { return false; } List<Account> accounts = service.getAccounts(); @@ -100,6 +97,7 @@ public class ExceptionHelper { Log.d(Config.LOGTAG, "using account=" + finalAccount.getJid().toBareJid() + " to send in stack trace"); + Conversation conversation = null; try { conversation = service.findOrCreateConversation(finalAccount, @@ -116,7 +114,7 @@ public class ExceptionHelper { @Override public void onClick(DialogInterface dialog, int which) { - preferences.edit().putBoolean("never_send", true) + preferences.edit().putBoolean("crash_report", false) .apply(); } }); diff --git a/src/main/java/eu/siacs/conversations/utils/GeoHelper.java b/src/main/java/eu/siacs/conversations/utils/GeoHelper.java index e2e9a212d..171e7dba6 100644 --- a/src/main/java/eu/siacs/conversations/utils/GeoHelper.java +++ b/src/main/java/eu/siacs/conversations/utils/GeoHelper.java @@ -78,4 +78,4 @@ public class GeoHelper { intents.add(httpIntent); return intents; } -} +}
\ No newline at end of file diff --git a/src/main/java/eu/siacs/conversations/utils/PhoneHelper.java b/src/main/java/eu/siacs/conversations/utils/PhoneHelper.java index e3a24fcfa..e77b2bae3 100644 --- a/src/main/java/eu/siacs/conversations/utils/PhoneHelper.java +++ b/src/main/java/eu/siacs/conversations/utils/PhoneHelper.java @@ -135,4 +135,8 @@ public class PhoneHelper { return "unknown"; } } + + public static String getOSVersion(Context context) { + return "Android/" + android.os.Build.MODEL + "/" + android.os.Build.VERSION.RELEASE; + } } diff --git a/src/main/java/eu/siacs/conversations/utils/Xmlns.java b/src/main/java/eu/siacs/conversations/utils/Xmlns.java index ad30b3e63..de0a29ce2 100644 --- a/src/main/java/eu/siacs/conversations/utils/Xmlns.java +++ b/src/main/java/eu/siacs/conversations/utils/Xmlns.java @@ -1,7 +1,5 @@ package eu.siacs.conversations.utils; -import eu.siacs.conversations.Config; - public final class Xmlns { public static final String BLOCKING = "urn:xmpp:blocking"; public static final String ROSTER = "jabber:iq:roster"; diff --git a/src/main/java/eu/siacs/conversations/utils/XmppUri.java b/src/main/java/eu/siacs/conversations/utils/XmppUri.java index 15a6c9a12..4039f8b0a 100644 --- a/src/main/java/eu/siacs/conversations/utils/XmppUri.java +++ b/src/main/java/eu/siacs/conversations/utils/XmppUri.java @@ -35,7 +35,7 @@ public class XmppUri { String scheme = uri.getScheme(); String host = uri.getHost(); List<String> segments = uri.getPathSegments(); - if ("https".equalsIgnoreCase(scheme) && "conversations.im".equalsIgnoreCase(host)) { + if ("https".equalsIgnoreCase(scheme) && "jabber.pix-art.de".equalsIgnoreCase(host)) { if (segments.size() >= 2 && segments.get(1).contains("@")) { // sample : https://conversations.im/i/foo@bar.com try { 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 diff --git a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java index 1128907e6..bd570d82e 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java @@ -26,8 +26,8 @@ import java.net.IDN; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.Socket; -import java.net.UnknownHostException; import java.net.URL; +import java.net.UnknownHostException; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.security.Principal; @@ -39,6 +39,7 @@ import java.util.Hashtable; import java.util.Iterator; import java.util.List; import java.util.Map.Entry; +import java.util.Random; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; @@ -257,7 +258,19 @@ public class XmppConnection implements Runnable { this.changeStatus(Account.State.CONNECTING); final boolean useTor = mXmppConnectionService.useTorToConnect() || account.isOnion(); final boolean extended = mXmppConnectionService.showExtendedConnectionOptions(); - if (useTor) { + if (Config.XMPP_IP != null && Config.XMPP_Ports != null) { + Integer[] XMPP_Port = Config.XMPP_Ports; + Integer Port = XMPP_Port[new Random().nextInt(XMPP_Port.length)]; + socket = new Socket(); + try { + socket.connect(new InetSocketAddress(Config.XMPP_IP, Port), Config.SOCKET_TIMEOUT * 1000); + } catch (IOException e) { + throw new IOException(); + } + Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": connect to " + Config.XMPP_IP + ":" + Port); + startXmpp(); + } + else if (useTor) { String destination; if (account.getHostname() == null || account.getHostname().isEmpty()) { destination = account.getServer().toString(); diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java index c9ee6bdc2..11b07e86f 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleConnection.java @@ -6,7 +6,9 @@ import android.util.Pair; import java.io.FileNotFoundException; import java.io.InputStream; import java.io.OutputStream; +import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.Locale; @@ -35,6 +37,7 @@ import eu.siacs.conversations.xmpp.jingle.stanzas.Reason; import eu.siacs.conversations.xmpp.stanzas.IqPacket; public class JingleConnection implements Transferable { + private final SimpleDateFormat fileDateFormat = new SimpleDateFormat("yyyyMMdd_HHmmssSSS", Locale.US); private JingleConnectionManager mJingleConnectionManager; private XmppConnectionService mXmppConnectionService; @@ -316,17 +319,18 @@ public class JingleConnection implements Transferable { if (fileNameElement != null) { String[] filename = fileNameElement.getContent() .toLowerCase(Locale.US).toLowerCase().split("\\."); + String filename_new = fileDateFormat.format(new Date(message.getTimeSent())); String extension = filename[filename.length - 1]; if (VALID_IMAGE_EXTENSIONS.contains(extension)) { message.setType(Message.TYPE_IMAGE); - message.setRelativeFilePath(message.getUuid()+"."+extension); + message.setRelativeFilePath(filename_new+"."+extension); } else if (VALID_CRYPTO_EXTENSIONS.contains( filename[filename.length - 1])) { if (filename.length == 3) { extension = filename[filename.length - 2]; if (VALID_IMAGE_EXTENSIONS.contains(extension)) { message.setType(Message.TYPE_IMAGE); - message.setRelativeFilePath(message.getUuid()+"."+extension); + message.setRelativeFilePath(filename_new+"."+extension); } else { message.setType(Message.TYPE_FILE); } @@ -350,7 +354,7 @@ public class JingleConnection implements Transferable { suffix = suffix.substring(0,suffix.length() - 4); } } - message.setRelativeFilePath(message.getUuid()+"_"+suffix); + message.setRelativeFilePath(filename_new+"_"+suffix); } long size = Long.parseLong(fileSize.getContent()); message.setBody(Long.toString(size)); diff --git a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java index 9240bd2c6..04724aab6 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java +++ b/src/main/java/eu/siacs/conversations/xmpp/jingle/JingleSocks5Transport.java @@ -7,15 +7,12 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.net.InetAddress; import java.net.InetSocketAddress; -import java.net.Proxy; import java.net.Socket; import java.net.SocketAddress; import java.net.UnknownHostException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; -import java.util.Arrays; import eu.siacs.conversations.Config; import eu.siacs.conversations.entities.DownloadableFile; |