diff --git a/TMessagesProj/src/main/AndroidManifest.xml b/TMessagesProj/src/main/AndroidManifest.xml index 12755bb70..60ce4b986 100644 --- a/TMessagesProj/src/main/AndroidManifest.xml +++ b/TMessagesProj/src/main/AndroidManifest.xml @@ -1,8 +1,8 @@ + android:versionCode="160" + android:versionName="1.3.21"> + @@ -164,6 +165,9 @@ + + + diff --git a/TMessagesProj/src/main/java/org/telegram/TL/TLClassStore.java b/TMessagesProj/src/main/java/org/telegram/TL/TLClassStore.java index e342b80d3..e67ac98f5 100644 --- a/TMessagesProj/src/main/java/org/telegram/TL/TLClassStore.java +++ b/TMessagesProj/src/main/java/org/telegram/TL/TLClassStore.java @@ -414,6 +414,7 @@ public class TLClassStore { classStore.put(TLRPC.TL_messageActionTTLChange.constructor, TLRPC.TL_messageActionTTLChange.class); classStore.put(TLRPC.TL_videoEncrypted.constructor, TLRPC.TL_videoEncrypted.class); classStore.put(TLRPC.TL_documentEncrypted.constructor, TLRPC.TL_documentEncrypted.class); + classStore.put(TLRPC.TL_audioEncrypted.constructor, TLRPC.TL_audioEncrypted.class); classStore.put(TLRPC.TL_gzip_packed.constructor, TLRPC.TL_gzip_packed.class); classStore.put(TLRPC.Vector.constructor, TLRPC.Vector.class); classStore.put(TLRPC.TL_userProfilePhotoOld.constructor, TLRPC.TL_userProfilePhotoOld.class); diff --git a/TMessagesProj/src/main/java/org/telegram/TL/TLRPC.java b/TMessagesProj/src/main/java/org/telegram/TL/TLRPC.java index f99c0f512..bbc4ab981 100644 --- a/TMessagesProj/src/main/java/org/telegram/TL/TLRPC.java +++ b/TMessagesProj/src/main/java/org/telegram/TL/TLRPC.java @@ -1227,16 +1227,6 @@ public class TLRPC { } } - public static class Audio extends TLObject { - public long id; - public long access_hash; - public int user_id; - public int date; - public int duration; - public int size; - public int dc_id; - } - public static class TL_audioEmpty extends Audio { public static int constructor = 0x586988d8; @@ -8776,6 +8766,19 @@ public class TLRPC { public byte[] iv; } + public static class Audio extends TLObject { + public long id; + public long access_hash; + public int user_id; + public int date; + public int duration; + public int size; + public int dc_id; + public String path; + public byte[] key; + public byte[] iv; + } + public static class MessageAction extends TLObject { public Photo photo; public UserProfilePhoto newUserPhoto; @@ -8871,6 +8874,36 @@ public class TLRPC { } } + public static class TL_audioEncrypted extends Audio { + public static int constructor = 0x555555F6; + + + public void readParams(SerializedData stream) { + id = stream.readInt64(); + access_hash = stream.readInt64(); + user_id = stream.readInt32(); + date = stream.readInt32(); + duration = stream.readInt32(); + size = stream.readInt32(); + dc_id = stream.readInt32(); + key = stream.readByteArray(); + iv = stream.readByteArray(); + } + + public void serializeToStream(SerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(id); + stream.writeInt64(access_hash); + stream.writeInt32(user_id); + stream.writeInt32(date); + stream.writeInt32(duration); + stream.writeInt32(size); + stream.writeInt32(dc_id); + stream.writeByteArray(key); + stream.writeByteArray(iv); + } + } + public static class TL_messageActionUserUpdatedPhoto extends MessageAction { public static int constructor = 0x55555551; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/BackgroundService.java b/TMessagesProj/src/main/java/org/telegram/messenger/BackgroundService.java new file mode 100644 index 000000000..d5e929230 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/BackgroundService.java @@ -0,0 +1,61 @@ +/* + * This is the source code of Telegram for Android v. 1.3.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013. + */ + +package org.telegram.messenger; + +import android.app.Service; +import android.content.Intent; +import android.os.Handler; +import android.os.IBinder; +import android.os.Looper; +import android.util.Log; + +public class BackgroundService extends Service { + + private Handler handler = new Handler(Looper.getMainLooper()); + private Runnable checkRunnable = new Runnable() { + @Override + public void run() { + check(); + } + }; + + public BackgroundService() { + + } + + @Override + public IBinder onBind(Intent intent) { + return null; + } + + @Override + public void onCreate() { + super.onCreate(); + check(); + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + super.onStartCommand(intent, flags, startId); + Log.e("tmessages", "onStartCommand"); + return START_STICKY; + } + + private void check() { + handler.removeCallbacks(checkRunnable); + handler.postDelayed(checkRunnable, 1500); + ConnectionsManager connectionsManager = ConnectionsManager.Instance; + } + + @Override + public void onDestroy() { + super.onDestroy(); + Log.e("tmessages", "onDestroy"); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ConnectionsManager.java b/TMessagesProj/src/main/java/org/telegram/messenger/ConnectionsManager.java index d9007a68f..940e82854 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ConnectionsManager.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ConnectionsManager.java @@ -15,7 +15,6 @@ import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.os.Build; import android.util.Base64; -import android.util.Log; import org.telegram.TL.TLClassStore; import org.telegram.TL.TLObject; @@ -38,6 +37,7 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection. public static int APP_ID = 2458; public static String APP_HASH = "5bce48dc7d331e62c955669eb7233217"; public static String HOCKEY_APP_HASH = "your-hockeyapp-api-key-here"; + public static boolean disableContactsImport = false; private HashMap datacenters = new HashMap(); private HashMap> processedMessageIdsSet = new HashMap>(); @@ -160,7 +160,7 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection. if (datacenters != null) { MessagesController.Instance.updateTimerProc(); if (datacenterWithId(currentDatacenterId).authKey != null) { - if (lastPingTime < System.currentTimeMillis() - 30000) { + if (lastPingTime < System.currentTimeMillis() - 19000) { lastPingTime = System.currentTimeMillis(); generatePing(); } @@ -947,6 +947,10 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection. } Datacenter requestDatacenter = datacenterWithId(datacenterId); + if (!request.initRequest && requestDatacenter.lastInitVersion != currentAppVersion) { + request.rpcRequest = wrapInLayer(request.rawRequest, requestDatacenter.datacenterId, request); + } + if (requestDatacenter == null) { if (!unknownDatacenterIds.contains(datacenterId)) { unknownDatacenterIds.add(datacenterId); @@ -1145,6 +1149,10 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection. } Datacenter requestDatacenter = datacenterWithId(datacenterId); + if (!request.initRequest && requestDatacenter.lastInitVersion != currentAppVersion) { + request.rpcRequest = wrapInLayer(request.rawRequest, requestDatacenter.datacenterId, request); + } + if (requestDatacenter == null) { unknownDatacenterIds.add(datacenterId); continue; @@ -1209,7 +1217,9 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection. long messageId = generateMessageId(); - SerializedData os = new SerializedData(); + boolean canCompress = (request.flags & RPCRequest.RPCRequestClassCanCompress) != 0; + + SerializedData os = new SerializedData(!canCompress); request.rpcRequest.serializeToStream(os); int requestLength = os.length(); @@ -1223,13 +1233,16 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection. sessionId = requestDatacenter.authUploadSessionId; } - if ((request.flags & RPCRequest.RPCRequestClassCanCompress) != 0) { + if (canCompress) { try { byte[] data = Utilities.compress(os.toByteArray()); if (data.length < requestLength) { TLRPC.TL_gzip_packed packed = new TLRPC.TL_gzip_packed(); packed.packed_data = data; request.rpcRequest = packed; + os = new SerializedData(true); + packed.serializeToStream(os); + requestLength = os.length(); } } catch (Exception e) { FileLog.e("tmessages", e); @@ -1431,7 +1444,7 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection. } TLRPC.TL_protoMessage wrapMessage(TLObject message, long sessionId, boolean meaningful) { - SerializedData os = new SerializedData(); + SerializedData os = new SerializedData(true); message.serializeToStream(os); if (os.length() != 0) { @@ -1463,7 +1476,7 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection. msgAck.msg_ids = new ArrayList(); msgAck.msg_ids.addAll(arr); - SerializedData os = new SerializedData(); + SerializedData os = new SerializedData(true); msgAck.serializeToStream(os); if (os.length() != 0) { @@ -1559,7 +1572,20 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection. NetworkMessage networkMessage = messages.get(0); TLRPC.TL_protoMessage message = networkMessage.protoMessage; - FileLog.d("tmessages", sessionId + ":Send message " + datacenter.datacenterId + "> Send message (" + message.seqno + ", " + message.msg_id + "): " + message.body); + if (DEBUG_VERSION) { + if (message.body instanceof TLRPC.invokeWithLayer11) { + FileLog.d("tmessages", sessionId + ":DC" + datacenter.datacenterId + "> Send message (" + message.seqno + ", " + message.msg_id + "): " + ((TLRPC.invokeWithLayer11)message.body).query); + } else if (message.body instanceof TLRPC.initConnection) { + TLRPC.initConnection r = (TLRPC.initConnection)message.body; + if (r.query instanceof TLRPC.invokeWithLayer11) { + FileLog.d("tmessages", sessionId + ":DC" + datacenter.datacenterId + "> Send message (" + message.seqno + ", " + message.msg_id + "): " + ((TLRPC.invokeWithLayer11)r.query).query); + } else { + FileLog.d("tmessages", sessionId + ":DC" + datacenter.datacenterId + "> Send message (" + message.seqno + ", " + message.msg_id + "): " + r.query); + } + } else { + FileLog.d("tmessages", sessionId + ":DC" + datacenter.datacenterId + "> Send message (" + message.seqno + ", " + message.msg_id + "): " + message.body); + } + } long msg_time = getTimeFromMsgId(message.msg_id); long currentTime = System.currentTimeMillis() + ((long)timeDifference) * 1000; @@ -1586,7 +1612,20 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection. for (NetworkMessage networkMessage : messages) { TLRPC.TL_protoMessage message = networkMessage.protoMessage; containerMessages.add(message); - FileLog.d("tmessages", sessionId + ":DC" + datacenter.datacenterId + "> Send message (" + message.seqno + ", " + message.msg_id + "): " + message.body); + if (DEBUG_VERSION) { + if (message.body instanceof TLRPC.invokeWithLayer11) { + FileLog.d("tmessages", sessionId + ":DC" + datacenter.datacenterId + "> Send message (" + message.seqno + ", " + message.msg_id + "): " + ((TLRPC.invokeWithLayer11)message.body).query); + } else if (message.body instanceof TLRPC.initConnection) { + TLRPC.initConnection r = (TLRPC.initConnection)message.body; + if (r.query instanceof TLRPC.invokeWithLayer11) { + FileLog.d("tmessages", sessionId + ":DC" + datacenter.datacenterId + "> Send message (" + message.seqno + ", " + message.msg_id + "): " + ((TLRPC.invokeWithLayer11)r.query).query); + } else { + FileLog.d("tmessages", sessionId + ":DC" + datacenter.datacenterId + "> Send message (" + message.seqno + ", " + message.msg_id + "): " + r.query); + } + } else { + FileLog.d("tmessages", sessionId + ":DC" + datacenter.datacenterId + "> Send message (" + message.seqno + ", " + message.msg_id + "): " + message.body); + } + } } messageContainer.messages = containerMessages; @@ -2339,7 +2378,11 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection. try { ConnectivityManager cm = (ConnectivityManager)ApplicationLoader.applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo[] networkInfos = cm.getAllNetworkInfo(); - for (NetworkInfo info : networkInfos) { + for (int a = 0; a < 2; a++) { + if (a >= networkInfos.length) { + break; + } + NetworkInfo info = networkInfos[a]; FileLog.e("tmessages", "Network: " + info.getTypeName() + " status: " + info.getState() + " info: " + info.getExtraInfo() + " object: " + info.getDetailedState() + " other: " + info); } if (networkInfos.length == 0) { @@ -2438,6 +2481,8 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection. } else { if (datacenter.authKeyId == null || !Arrays.equals(keyId, datacenter.authKeyId)) { FileLog.e("tmessages", "Error: invalid auth key id " + connection); + connection.suspendConnection(true); + connection.connect(); return; } @@ -2449,6 +2494,8 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection. messageData = Utilities.aesIgeEncryption(messageData, keyData.aesKey, keyData.aesIv, false, false); if (messageData == null) { FileLog.e("tmessages", "Error: can't decrypt message data " + connection); + connection.suspendConnection(true); + connection.connect(); return; } @@ -2490,6 +2537,8 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection. if (!Arrays.equals(messageKey, realMessageKey)) { FileLog.e("tmessages", "***** Error: invalid message key"); + connection.suspendConnection(true); + connection.connect(); return; } @@ -2551,7 +2600,7 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection. public void run() { moveToDatacenter(datacenterId); } - }, 1000, false); + }, 1000); } } }, null, true, RPCRequest.RPCRequestClassGeneric, currentDatacenterId); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ConnectionsManager2.java b/TMessagesProj/src/main/java/org/telegram/messenger/ConnectionsManager2.java new file mode 100644 index 000000000..d9007a68f --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ConnectionsManager2.java @@ -0,0 +1,2670 @@ +/* + * This is the source code of Telegram for Android v. 1.3.2. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013. + */ + +package org.telegram.messenger; + +import android.content.Context; +import android.content.SharedPreferences; +import android.content.pm.PackageInfo; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.os.Build; +import android.util.Base64; +import android.util.Log; + +import org.telegram.TL.TLClassStore; +import org.telegram.TL.TLObject; +import org.telegram.TL.TLRPC; +import org.telegram.ui.ApplicationLoader; + +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Locale; +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.ConcurrentHashMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class ConnectionsManager implements Action.ActionDelegate, TcpConnection.TcpConnectionDelegate { + public static boolean DEBUG_VERSION = true; + public static int APP_ID = 2458; + public static String APP_HASH = "5bce48dc7d331e62c955669eb7233217"; + public static String HOCKEY_APP_HASH = "your-hockeyapp-api-key-here"; + + private HashMap datacenters = new HashMap(); + private HashMap> processedMessageIdsSet = new HashMap>(); + private HashMap nextSeqNoInSession = new HashMap(); + private ArrayList sessionsToDestroy = new ArrayList(); + private ArrayList destroyingSessions = new ArrayList(); + private HashMap> quickAckIdToRequestIds = new HashMap>(); + private HashMap> messagesIdsForConfirmation = new HashMap>(); + private HashMap> processedSessionChanges = new HashMap>(); + private HashMap pingIdToDate = new HashMap(); + private ConcurrentHashMap> requestsByGuids = new ConcurrentHashMap>(100, 1.0f, 2); + private ConcurrentHashMap requestsByClass = new ConcurrentHashMap(100, 1.0f, 2); + public volatile int connectionState = 2; + + private ArrayList requestQueue = new ArrayList(); + private ArrayList runningRequests = new ArrayList(); + private ArrayList actionQueue = new ArrayList(); + + private TLRPC.TL_auth_exportedAuthorization movingAuthorization; + public static final int DEFAULT_DATACENTER_ID = Integer.MAX_VALUE; + public static final int DC_UPDATE_TIME = 60 * 60; + public int currentDatacenterId; + public int movingToDatacenterId; + private long lastOutgoingMessageId = 0; + private int useDifferentBackend = 0; + private final int SESSION_VERSION = 2; + public int timeDifference = 0; + public int currentPingTime; + private int lastDestroySessionRequestTime; + private final boolean isDebugSession = false; + private boolean updatingDcSettings = false; + private int updatingDcStartTime = 0; + private int lastDcUpdateTime = 0; + private int currentAppVersion = 0; + + public static ConnectionsManager Instance = new ConnectionsManager(); + + private boolean paused = false; + private Runnable stageRunnable; + private Runnable pingRunnable; + private long lastPingTime = System.currentTimeMillis(); + private int nextWakeUpTimeout = 60000; + private int nextSleepTimeout = 60000; + + public ConnectionsManager() { + currentAppVersion = ApplicationLoader.getAppVersion(); + lastOutgoingMessageId = 0; + movingToDatacenterId = DEFAULT_DATACENTER_ID; + loadSession(); + + if (!isNetworkOnline()) { + connectionState = 1; + } + + Timer serviceTimer = new Timer(); + serviceTimer.schedule(new TimerTask() { + @Override + public void run() { + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + long currentTime = System.currentTimeMillis(); + if (ApplicationLoader.lastPauseTime != 0 && ApplicationLoader.lastPauseTime < currentTime - nextSleepTimeout) { + boolean dontSleep = false; + for (RPCRequest request : runningRequests) { + if (request.retryCount < 10 && (request.runningStartTime + 60 > (int)(currentTime / 1000)) && ((request.flags & RPCRequest.RPCRequestClassDownloadMedia) != 0 || (request.flags & RPCRequest.RPCRequestClassUploadMedia) != 0)) { + dontSleep = true; + break; + } + } + if (!dontSleep) { + for (RPCRequest request : requestQueue) { + if ((request.flags & RPCRequest.RPCRequestClassDownloadMedia) != 0 || (request.flags & RPCRequest.RPCRequestClassUploadMedia) != 0) { + dontSleep = true; + break; + } + } + } + if (!dontSleep) { + if (!paused) { + FileLog.e("tmessages", "pausing network and timers by sleep time = " + nextSleepTimeout); + for (Datacenter datacenter : datacenters.values()) { + if (datacenter.connection != null) { + datacenter.connection.suspendConnection(true); + } + if (datacenter.uploadConnection != null) { + datacenter.uploadConnection.suspendConnection(true); + } + if (datacenter.downloadConnection != null) { + datacenter.downloadConnection.suspendConnection(true); + } + } + } + try { + paused = true; + if (ApplicationLoader.lastPauseTime < currentTime - nextSleepTimeout - nextWakeUpTimeout) { + ApplicationLoader.lastPauseTime = currentTime; + nextSleepTimeout = 30000; + FileLog.e("tmessages", "wakeup network in background by wakeup time = " + nextWakeUpTimeout); + if (nextWakeUpTimeout < 30 * 60 * 1000) { + nextWakeUpTimeout *= 2; + } + } else { + Thread.sleep(500); + return; + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } else { + ApplicationLoader.lastPauseTime += 30 * 1000; + FileLog.e("tmessages", "don't sleep 30 seconds because of upload or download request"); + } + } + if (paused) { + paused = false; + FileLog.e("tmessages", "resume network and timers"); + } + + if (datacenters != null) { + MessagesController.Instance.updateTimerProc(); + if (datacenterWithId(currentDatacenterId).authKey != null) { + if (lastPingTime < System.currentTimeMillis() - 30000) { + lastPingTime = System.currentTimeMillis(); + generatePing(); + } + if (!updatingDcSettings && lastDcUpdateTime < (int)(System.currentTimeMillis() / 1000) - DC_UPDATE_TIME) { + updateDcSettings(); + } + processRequestQueue(0, 0); + } + } + } + }); + } + }, 1000, 1000); + } + + public void resumeNetworkMaybe() { + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + if (paused) { + ApplicationLoader.lastPauseTime = System.currentTimeMillis(); + nextWakeUpTimeout = 60000; + nextSleepTimeout = 30000; + FileLog.e("tmessages", "wakeup network in background by recieved push"); + } else if (ApplicationLoader.lastPauseTime != 0) { + ApplicationLoader.lastPauseTime = System.currentTimeMillis(); + FileLog.e("tmessages", "reset sleep timeout by recieved push"); + } + } + }); + } + + public void applicationMovedToForeground() { + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + if (paused) { + nextSleepTimeout = 60000; + nextWakeUpTimeout = 60000; + FileLog.e("tmessages", "reset timers by application moved to foreground"); + } + } + }); + } + + //================================================================================ + // Config and session manage + //================================================================================ + + public Datacenter datacenterWithId(int datacenterId) { + if (datacenterId == DEFAULT_DATACENTER_ID) { + return datacenters.get(currentDatacenterId); + } + return datacenters.get(datacenterId); + } + + void setTimeDifference(int diff) { + boolean store = Math.abs(diff - timeDifference) > 25; + timeDifference = diff; + if (store) { + saveSession(); + } + } + + void loadSession() { + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + File configFile = new File(ApplicationLoader.applicationContext.getFilesDir(), "config.dat"); + if (configFile.exists()) { + try { + SerializedData data = new SerializedData(configFile); + int datacenterSetId = data.readInt32(); + int version = data.readInt32(); + + if (datacenterSetId == useDifferentBackend && version == SESSION_VERSION) { + sessionsToDestroy.clear(); + int count = data.readInt32(); + for (int a = 0; a < count; a++) { + sessionsToDestroy.add(data.readInt64()); + } + timeDifference = data.readInt32(); + count = data.readInt32(); + for (int a = 0; a < count; a++) { + Datacenter datacenter = new Datacenter(data, 0); + datacenters.put(datacenter.datacenterId, datacenter); + } + currentDatacenterId = data.readInt32(); + } else { + UserConfig.clearConfig(); + } + } catch (Exception e) { + UserConfig.clearConfig(); + } + } else { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("dataconfig", Context.MODE_PRIVATE); + int datacenterSetId = preferences.getInt("datacenterSetId", 0); + if (datacenterSetId == useDifferentBackend) { + currentDatacenterId = preferences.getInt("currentDatacenterId", 0); + timeDifference = preferences.getInt("timeDifference", 0); + lastDcUpdateTime = preferences.getInt("lastDcUpdateTime", 0); + try { + sessionsToDestroy.clear(); + String sessionsString = preferences.getString("sessionsToDestroy", null); + if (sessionsString != null) { + byte[] sessionsBytes = Base64.decode(sessionsString, Base64.DEFAULT); + if (sessionsBytes != null) { + SerializedData data = new SerializedData(sessionsBytes); + int count = data.readInt32(); + for (int a = 0; a < count; a++) { + sessionsToDestroy.add(data.readInt64()); + } + } + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + + try { + String datacentersString = preferences.getString("datacenters", null); + if (datacentersString != null) { + byte[] datacentersBytes = Base64.decode(datacentersString, Base64.DEFAULT); + if (datacentersBytes != null) { + SerializedData data = new SerializedData(datacentersBytes); + int count = data.readInt32(); + for (int a = 0; a < count; a++) { + Datacenter datacenter = new Datacenter(data, 1); + datacenters.put(datacenter.datacenterId, datacenter); + } + } + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + } + + if (currentDatacenterId != 0 && UserConfig.clientActivated) { + Datacenter datacenter = datacenterWithId(currentDatacenterId); + if (datacenter.authKey == null) { + currentDatacenterId = 0; + datacenters.clear(); + UserConfig.clearConfig(); + } + } + + if (datacenters.size() == 0) { + if (useDifferentBackend == 0) { + Datacenter datacenter = new Datacenter(); + datacenter.datacenterId = 1; + datacenter.addAddressAndPort("173.240.5.1", 443); + datacenters.put(datacenter.datacenterId, datacenter); + + datacenter = new Datacenter(); + datacenter.datacenterId = 2; + datacenter.addAddressAndPort("95.142.192.66", 443); + datacenters.put(datacenter.datacenterId, datacenter); + + datacenter = new Datacenter(); + datacenter.datacenterId = 3; + datacenter.addAddressAndPort("174.140.142.6", 443); + datacenters.put(datacenter.datacenterId, datacenter); + + datacenter = new Datacenter(); + datacenter.datacenterId = 4; + datacenter.addAddressAndPort("31.210.235.12", 443); + datacenters.put(datacenter.datacenterId, datacenter); + + datacenter = new Datacenter(); + datacenter.datacenterId = 5; + datacenter.addAddressAndPort("116.51.22.2", 443); + datacenters.put(datacenter.datacenterId, datacenter); + } else { + Datacenter datacenter = new Datacenter(); + datacenter.datacenterId = 1; + datacenter.addAddressAndPort("173.240.5.253", 443); + datacenters.put(datacenter.datacenterId, datacenter); + + datacenter = new Datacenter(); + datacenter.datacenterId = 2; + datacenter.addAddressAndPort("95.142.192.65", 443); + datacenters.put(datacenter.datacenterId, datacenter); + + datacenter = new Datacenter(); + datacenter.datacenterId = 3; + datacenter.addAddressAndPort("174.140.142.5", 443); + datacenters.put(datacenter.datacenterId, datacenter); + } + } else if (datacenters.size() == 1) { + Datacenter datacenter = new Datacenter(); + datacenter.datacenterId = 2; + datacenter.addAddressAndPort("95.142.192.66", 443); + datacenters.put(datacenter.datacenterId, datacenter); + + datacenter = new Datacenter(); + datacenter.datacenterId = 3; + datacenter.addAddressAndPort("174.140.142.6", 443); + datacenters.put(datacenter.datacenterId, datacenter); + + datacenter = new Datacenter(); + datacenter.datacenterId = 4; + datacenter.addAddressAndPort("31.210.235.12", 443); + datacenters.put(datacenter.datacenterId, datacenter); + + datacenter = new Datacenter(); + datacenter.datacenterId = 5; + datacenter.addAddressAndPort("116.51.22.2", 443); + datacenters.put(datacenter.datacenterId, datacenter); + } + + for (Datacenter datacenter : datacenters.values()) { + datacenter.authSessionId = getNewSessionId(); + } + + if (datacenters.size() != 0 && currentDatacenterId == 0) { + currentDatacenterId = 1; + saveSession(); + } + movingToDatacenterId = DEFAULT_DATACENTER_ID; + } + }); + } + + void saveSession() { + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + try { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("dataconfig", Context.MODE_PRIVATE); + SharedPreferences.Editor editor = preferences.edit(); + editor.putInt("datacenterSetId", useDifferentBackend); + Datacenter currentDatacenter = datacenterWithId(currentDatacenterId); + if (currentDatacenter != null) { + editor.putInt("currentDatacenterId", currentDatacenterId); + editor.putInt("timeDifference", timeDifference); + editor.putInt("lastDcUpdateTime", lastDcUpdateTime); + + ArrayList sessions = new ArrayList(); + if (currentDatacenter.authSessionId != 0) { + sessions.add(currentDatacenter.authSessionId); + } + if (currentDatacenter.authDownloadSessionId != 0) { + sessions.add(currentDatacenter.authDownloadSessionId); + } + if (currentDatacenter.authUploadSessionId != 0) { + sessions.add(currentDatacenter.authUploadSessionId); + } + + if (!sessions.isEmpty()) { + SerializedData data = new SerializedData(sessions.size() * 8 + 4); + data.writeInt32(sessions.size()); + for (long session : sessions) { + data.writeInt64(session); + } + editor.putString("sessionsToDestroy", Base64.encodeToString(data.toByteArray(), Base64.DEFAULT)); + } else { + editor.remove("sessionsToDestroy"); + } + + if (!datacenters.isEmpty()) { + SerializedData data = new SerializedData(); + data.writeInt32(datacenters.size()); + for (Datacenter datacenter : datacenters.values()) { + datacenter.SerializeToStream(data); + } + editor.putString("datacenters", Base64.encodeToString(data.toByteArray(), Base64.DEFAULT)); + } else { + editor.remove("datacenters"); + } + } else { + editor.remove("datacenters"); + editor.remove("sessionsToDestroy"); + editor.remove("currentDatacenterId"); + editor.remove("timeDifference"); + } + editor.commit(); + File configFile = new File(ApplicationLoader.applicationContext.getFilesDir(), "config.dat"); + if (configFile.exists()) { + configFile.delete(); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + void clearRequestsForRequestClass(int requestClass, Datacenter datacenter) { + for (RPCRequest request : runningRequests) { + Datacenter dcenter = datacenterWithId(request.runningDatacenterId); + if ((request.flags & requestClass) != 0 && dcenter != null && dcenter.datacenterId == datacenter.datacenterId) { + request.runningMessageId = 0; + request.runningMessageSeqNo = 0; + request.runningStartTime = 0; + request.runningMinStartTime = 0; + request.transportChannelToken = 0; + } + } + } + + public void cleanUp() { + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + Datacenter datacenter = datacenterWithId(currentDatacenterId); + recreateSession(datacenter.authSessionId, datacenter); + } + }); + } + + void recreateSession(long sessionId, Datacenter datacenter) { + messagesIdsForConfirmation.remove(sessionId); + processedMessageIdsSet.remove(sessionId); + nextSeqNoInSession.remove(sessionId); + processedSessionChanges.remove(sessionId); + pingIdToDate.remove(sessionId); + + if (sessionId == datacenter.authSessionId) { + clearRequestsForRequestClass(RPCRequest.RPCRequestClassGeneric, datacenter); + FileLog.d("tmessages", "***** Recreate generic session"); + datacenter.authSessionId = getNewSessionId(); + } + } + + long getNewSessionId() { + long newSessionId = (long)(MessagesController.random.nextDouble() * Long.MAX_VALUE); + return isDebugSession ? (0xabcd000000000000L | (newSessionId & 0x0000ffffffffffffL)) : newSessionId; + } + + long generateMessageId() { + long messageId = (long)((((double)System.currentTimeMillis() + ((double)timeDifference) * 1000) * 4294967296.0) / 1000.0); + if (messageId <= lastOutgoingMessageId) { + messageId = lastOutgoingMessageId + 1; + } + while (messageId % 4 != 0) { + messageId++; + } + lastOutgoingMessageId = messageId; + return messageId; + } + + long getTimeFromMsgId(long messageId) { + return (long)(messageId / 4294967296.0 * 1000); + } + + int generateMessageSeqNo(long session, boolean increment) { + int value = 0; + if (nextSeqNoInSession.containsKey(session)) { + value = nextSeqNoInSession.get(session); + } + if (increment) { + nextSeqNoInSession.put(session, value + 1); + } + return value * 2 + (increment ? 1 : 0); + } + + boolean isMessageIdProcessed(long sessionId, long messageId) { + ArrayList set = processedMessageIdsSet.get(sessionId); + return set != null && set.contains(messageId); + } + + void addProcessedMessageId(long sessionId, long messageId) { + ArrayList set = processedMessageIdsSet.get(sessionId); + if (set != null) { + final int eraseLimit = 1000; + final int eraseThreshold = 224; + + if (set.size() > eraseLimit + eraseThreshold) { + for (int a = 0; a < Math.min(set.size(), eraseThreshold + 1); a++) { + set.remove(0); + } + } + set.add(messageId); + } else { + ArrayList sessionMap = new ArrayList(); + sessionMap.add(messageId); + processedMessageIdsSet.put(sessionId, sessionMap); + } + } + + //================================================================================ + // Requests manage + //================================================================================ + int lastClassGuid = 1; + public int generateClassGuid() { + int guid = lastClassGuid++; + ArrayList requests = new ArrayList(); + requestsByGuids.put(guid, requests); + return guid; + } + + public void cancelRpcsForClassGuid(int guid) { + ArrayList requests = requestsByGuids.get(guid); + if (requests != null) { + for (Long request : requests) { + cancelRpc(request, true); + } + requestsByGuids.remove(guid); + } + } + + public void bindRequestToGuid(final Long request, final int guid) { + Utilities.RunOnUIThread(new Runnable() { + @Override + public void run() { + ArrayList requests = requestsByGuids.get(guid); + if (requests != null) { + requests.add(request); + requestsByClass.put(request, guid); + } + } + }); + } + + public void removeRequestInClass(final Long request) { + Utilities.RunOnUIThread(new Runnable() { + @Override + public void run() { + Integer guid = requestsByClass.get(request); + if (guid != null) { + ArrayList requests = requestsByGuids.get(guid); + if (requests != null) { + requests.remove(request); + } + } + } + }); + } + + public void updateDcSettings() { + if (updatingDcSettings) { + return; + } + updatingDcStartTime = (int)(System.currentTimeMillis() / 1000); + updatingDcSettings = true; + TLRPC.TL_help_getConfig getConfig = new TLRPC.TL_help_getConfig(); + + ConnectionsManager.Instance.performRpc(getConfig, new RPCRequest.RPCRequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + if (!updatingDcSettings) { + return; + } + if (error == null) { + lastDcUpdateTime = (int)(System.currentTimeMillis() / 1000); + TLRPC.TL_config config = (TLRPC.TL_config)response; + ArrayList datacentersArr = new ArrayList(); + HashMap datacenterMap = new HashMap(); + for (TLRPC.TL_dcOption datacenterDesc : config.dc_options) { + Datacenter existing = datacenterMap.get(datacenterDesc.id); + if (existing == null) { + existing = new Datacenter(); + existing.datacenterId = datacenterDesc.id; + existing.authSessionId = (long)(MessagesController.random.nextDouble() * Long.MAX_VALUE); + datacentersArr.add(existing); + datacenterMap.put(existing.datacenterId, existing); + } + existing.addAddressAndPort(datacenterDesc.ip_address, datacenterDesc.port); + } + + if (!datacentersArr.isEmpty()) { + for (Datacenter datacenter : datacentersArr) { + Datacenter exist = datacenterWithId(datacenter.datacenterId); + if (exist == null) { + datacenters.put(datacenter.datacenterId, datacenter); + } else { + exist.replaceAddressesAndPorts(datacenter.addresses, datacenter.ports); + } + if (datacenter.datacenterId == movingToDatacenterId) { + movingToDatacenterId = DEFAULT_DATACENTER_ID; + moveToDatacenter(datacenter.datacenterId); + } + } + saveSession(); + + processRequestQueue(RPCRequest.RPCRequestClassTransportMask, 0); + } + } + updatingDcSettings = false; + } + }, null, true, RPCRequest.RPCRequestClassEnableUnauthorized | RPCRequest.RPCRequestClassGeneric, currentDatacenterId); + } + + public long performRpc(final TLObject rpc, final RPCRequest.RPCRequestDelegate completionBlock, final RPCRequest.RPCProgressDelegate progressBlock, boolean requiresCompletion, int requestClass) { + return performRpc(rpc, completionBlock, progressBlock, requiresCompletion, requestClass, DEFAULT_DATACENTER_ID); + } + + public long performRpc(final TLObject rpc, final RPCRequest.RPCRequestDelegate completionBlock, final RPCRequest.RPCProgressDelegate progressBlock, boolean requiresCompletion, int requestClass, int datacenterId) { + return performRpc(rpc, completionBlock, progressBlock, null, requiresCompletion, requestClass, datacenterId); + } + + TLObject wrapInLayer(TLObject object, int datacenterId, RPCRequest request) { + if (object.layer() > 0) { + Datacenter datacenter = datacenterWithId(datacenterId); + if (datacenter == null || datacenter.lastInitVersion != currentAppVersion) { + request.initRequest = true; + TLRPC.initConnection invoke = new TLRPC.initConnection(); + invoke.query = object; + invoke.api_id = APP_ID; + try { + invoke.lang_code = Locale.getDefault().getCountry(); + invoke.device_model = Build.MANUFACTURER + Build.MODEL; + if (invoke.device_model == null) { + invoke.device_model = "Android unknown"; + } + PackageInfo pInfo = ApplicationLoader.applicationContext.getPackageManager().getPackageInfo(ApplicationLoader.applicationContext.getPackageName(), 0); + invoke.app_version = pInfo.versionName; + if (invoke.app_version == null) { + invoke.app_version = "App version unknown"; + } + invoke.system_version = "SDK " + Build.VERSION.SDK_INT; + } catch (Exception e) { + FileLog.e("tmessages", e); + invoke.lang_code = "en"; + invoke.device_model = "Android unknown"; + invoke.app_version = "App version unknown"; + invoke.system_version = "SDK " + Build.VERSION.SDK_INT; + } + if (invoke.lang_code == null || invoke.lang_code.length() == 0) { + invoke.lang_code = "en"; + } + if (invoke.device_model == null || invoke.device_model.length() == 0) { + invoke.device_model = "Android unknown"; + } + if (invoke.app_version == null || invoke.app_version.length() == 0) { + invoke.app_version = "App version unknown"; + } + if (invoke.system_version == null || invoke.system_version.length() == 0) { + invoke.system_version = "SDK Unknown"; + } + object = invoke; + } + TLRPC.invokeWithLayer11 invoke = new TLRPC.invokeWithLayer11(); + invoke.query = object; + FileLog.d("wrap in layer", "" + object); + return invoke; + } + return object; + } + + public static volatile long nextCallToken = 0; + long performRpc(final TLObject rpc, final RPCRequest.RPCRequestDelegate completionBlock, final RPCRequest.RPCProgressDelegate progressBlock, final RPCRequest.RPCQuickAckDelegate quickAckBlock, final boolean requiresCompletion, final int requestClass, final int datacenterId) { + + final long requestToken = nextCallToken++; + + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + RPCRequest request = new RPCRequest(); + request.token = requestToken; + request.flags = requestClass; + + request.runningDatacenterId = datacenterId; + + request.rawRequest = rpc; + request.rpcRequest = wrapInLayer(rpc, datacenterId, request); + request.completionBlock = completionBlock; + request.progressBlock = progressBlock; + request.quickAckBlock = quickAckBlock; + request.requiresCompletion = requiresCompletion; + + requestQueue.add(request); + + if (paused && ((request.flags & RPCRequest.RPCRequestClassDownloadMedia) != 0 || (request.flags & RPCRequest.RPCRequestClassUploadMedia) != 0)) { + ApplicationLoader.lastPauseTime = System.currentTimeMillis(); + nextSleepTimeout = 30000; + FileLog.e("tmessages", "wakeup by download or upload request"); + } + + processRequestQueue(0, 0); + } + }); + + return requestToken; + } + + public void cancelRpc(final long token, final boolean notifyServer) { + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + boolean found = false; + + for (int i = 0; i < requestQueue.size(); i++) { + RPCRequest request = requestQueue.get(i); + if (request.token == token) { + found = true; + request.cancelled = true; + FileLog.d("tmessages", "===== Cancelled queued rpc request " + request.rawRequest); + requestQueue.remove(i); + break; + } + } + + for (int i = 0; i < runningRequests.size(); i++) { + RPCRequest request = runningRequests.get(i); + if (request.token == token) { + found = true; + + FileLog.d("tmessages", "===== Cancelled running rpc request " + request.rawRequest); + + if ((request.flags & RPCRequest.RPCRequestClassGeneric) != 0) { + if (notifyServer) { + TLRPC.TL_rpc_drop_answer dropAnswer = new TLRPC.TL_rpc_drop_answer(); + dropAnswer.req_msg_id = request.runningMessageId; + performRpc(dropAnswer, null, null, false, request.flags); + } + } + + request.cancelled = true; + runningRequests.remove(i); + break; + } + } + if (!found) { + FileLog.d("tmessages", "***** Warning: cancelling unknown request"); + } + } + }); + } + + public static boolean isNetworkOnline() { + boolean status = false; + try { + ConnectivityManager cm = (ConnectivityManager)ApplicationLoader.applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo netInfo = cm.getNetworkInfo(0); + if (netInfo != null && netInfo.getState() == NetworkInfo.State.CONNECTED) { + status = true; + } else { + netInfo = cm.getNetworkInfo(1); + if(netInfo != null && netInfo.getState() == NetworkInfo.State.CONNECTED) { + status = true; + } + } + } catch(Exception e) { + FileLog.e("tmessages", e); + return false; + } + return status; + } + + public int getCurrentTime() { + return (int)(System.currentTimeMillis() / 1000) + timeDifference; + } + + private void processRequestQueue(int requestClass, int _datacenterId) { + final HashMap activeTransportTokens = new HashMap(); + final ArrayList transportsToResume = new ArrayList(); + + final HashMap activeDownloadTransportTokens = new HashMap(); + final ArrayList downloadTransportsToResume = new ArrayList(); + + final HashMap activeUploadTransportTokens = new HashMap(); + final ArrayList uploadTransportsToResume = new ArrayList(); + + for (Datacenter datacenter : datacenters.values()) { + if (datacenter.connection != null) { + int channelToken = datacenter.connection.channelToken; + if (channelToken != 0) { + activeTransportTokens.put(datacenter.datacenterId, channelToken); + } + } + if (datacenter.downloadConnection != null) { + int channelToken = datacenter.downloadConnection.channelToken; + if (channelToken != 0) { + activeDownloadTransportTokens.put(datacenter.datacenterId, channelToken); + } + } + if (datacenter.uploadConnection != null) { + int channelToken = datacenter.uploadConnection.channelToken; + if (channelToken != 0) { + activeUploadTransportTokens.put(datacenter.datacenterId, channelToken); + } + } + } + for (RPCRequest request : runningRequests) { + if ((request.flags & RPCRequest.RPCRequestClassGeneric) != 0) { + Datacenter requestDatacenter = datacenterWithId(request.runningDatacenterId); + if (requestDatacenter != null && !activeTransportTokens.containsKey(requestDatacenter.datacenterId) && !transportsToResume.contains(requestDatacenter.datacenterId)) { + transportsToResume.add(requestDatacenter.datacenterId); + } + } else if ((request.flags & RPCRequest.RPCRequestClassDownloadMedia) != 0) { + Datacenter requestDatacenter = datacenterWithId(request.runningDatacenterId); + if (requestDatacenter != null && !activeDownloadTransportTokens.containsKey(requestDatacenter.datacenterId) && !downloadTransportsToResume.contains(requestDatacenter.datacenterId)) { + downloadTransportsToResume.add(requestDatacenter.datacenterId); + } + } else if ((request.flags & RPCRequest.RPCRequestClassUploadMedia) != 0) { + Datacenter requestDatacenter = datacenterWithId(request.runningDatacenterId); + if (requestDatacenter != null && !activeUploadTransportTokens.containsKey(requestDatacenter.datacenterId) && !uploadTransportsToResume.contains(requestDatacenter.datacenterId)) { + uploadTransportsToResume.add(requestDatacenter.datacenterId); + } + } + } + for (RPCRequest request : requestQueue) { + if ((request.flags & RPCRequest.RPCRequestClassGeneric) != 0) { + Datacenter requestDatacenter = datacenterWithId(request.runningDatacenterId); + if (requestDatacenter != null && !activeTransportTokens.containsKey(requestDatacenter.datacenterId) && !transportsToResume.contains(requestDatacenter.datacenterId)) { + transportsToResume.add(requestDatacenter.datacenterId); + } + } else if ((request.flags & RPCRequest.RPCRequestClassDownloadMedia) != 0) { + Datacenter requestDatacenter = datacenterWithId(request.runningDatacenterId); + if (requestDatacenter != null && !activeDownloadTransportTokens.containsKey(requestDatacenter.datacenterId) && !downloadTransportsToResume.contains(requestDatacenter.datacenterId)) { + downloadTransportsToResume.add(requestDatacenter.datacenterId); + } + } else if ((request.flags & RPCRequest.RPCRequestClassUploadMedia) != 0) { + Datacenter requestDatacenter = datacenterWithId(request.runningDatacenterId); + if (requestDatacenter != null && !activeUploadTransportTokens.containsKey(requestDatacenter.datacenterId) && !uploadTransportsToResume.contains(requestDatacenter.datacenterId)) { + uploadTransportsToResume.add(requestDatacenter.datacenterId); + } + } + } + + boolean haveNetwork = true;//activeTransportTokens.size() != 0 || isNetworkOnline(); + + if (!activeTransportTokens.containsKey(currentDatacenterId) && !transportsToResume.contains(currentDatacenterId)) { + transportsToResume.add(currentDatacenterId); + } + + for (int it : transportsToResume) { + Datacenter datacenter = datacenterWithId(it); + if (datacenter.authKey != null) { + if (datacenter.connection == null) { + datacenter.connection = new TcpConnection(datacenter.datacenterId); + datacenter.connection.delegate = this; + datacenter.connection.transportRequestClass = RPCRequest.RPCRequestClassGeneric; + } + datacenter.connection.connect(); + } + } + for (int it : downloadTransportsToResume) { + Datacenter datacenter = datacenterWithId(it); + if (datacenter.authKey != null) { + if (datacenter.downloadConnection == null) { + datacenter.downloadConnection = new TcpConnection(datacenter.datacenterId); + datacenter.downloadConnection.delegate = this; + datacenter.downloadConnection.transportRequestClass = RPCRequest.RPCRequestClassDownloadMedia; + datacenter.authDownloadSessionId = getNewSessionId(); + } + datacenter.downloadConnection.connect(); + } + } + for (int it : uploadTransportsToResume) { + Datacenter datacenter = datacenterWithId(it); + if (datacenter.authKey != null) { + if (datacenter.uploadConnection == null) { + datacenter.uploadConnection = new TcpConnection(datacenter.datacenterId); + datacenter.uploadConnection.delegate = this; + datacenter.uploadConnection.transportRequestClass = RPCRequest.RPCRequestClassUploadMedia; + datacenter.authUploadSessionId = getNewSessionId(); + } + datacenter.uploadConnection.connect(); + } + } + + final HashMap> genericMessagesToDatacenters = new HashMap>(); + + final ArrayList unknownDatacenterIds = new ArrayList(); + final ArrayList neededDatacenterIds = new ArrayList(); + final ArrayList unauthorizedDatacenterIds = new ArrayList(); + + int currentTime = (int)(System.currentTimeMillis() / 1000); + for (RPCRequest request : runningRequests) { + if (updatingDcSettings && datacenters.size() > 1 && request.rawRequest instanceof TLRPC.TL_help_getConfig) { + if (updatingDcStartTime < currentTime - 60) { + updatingDcStartTime = currentTime; + ArrayList allDc = new ArrayList(datacenters.values()); + for (int a = 0; a < allDc.size(); a++) { + Datacenter dc = allDc.get(a); + if (dc.datacenterId == request.runningDatacenterId) { + allDc.remove(a); + break; + } + } + Datacenter newDc = allDc.get(Math.abs(MessagesController.random.nextInt()) % allDc.size()); + request.runningDatacenterId = newDc.datacenterId; + } + } + + int datacenterId = request.runningDatacenterId; + if (datacenterId == DEFAULT_DATACENTER_ID) { + if (movingToDatacenterId != DEFAULT_DATACENTER_ID) { + continue; + } + datacenterId = currentDatacenterId; + } + + Datacenter requestDatacenter = datacenterWithId(datacenterId); + if (requestDatacenter == null) { + if (!unknownDatacenterIds.contains(datacenterId)) { + unknownDatacenterIds.add(datacenterId); + } + continue; + } else if (requestDatacenter.authKey == null) { + if (!neededDatacenterIds.contains(datacenterId)) { + neededDatacenterIds.add(datacenterId); + } + continue; + } else if (!requestDatacenter.authorized && request.runningDatacenterId != DEFAULT_DATACENTER_ID && request.runningDatacenterId != currentDatacenterId && (request.flags & RPCRequest.RPCRequestClassEnableUnauthorized) == 0) { + if (!unauthorizedDatacenterIds.contains(datacenterId)) { + unauthorizedDatacenterIds.add(datacenterId); + } + continue; + } + + Integer tokenIt = activeTransportTokens.get(requestDatacenter.datacenterId); + int datacenterTransportToken = tokenIt != null ? tokenIt : 0; + + Integer uploadTokenIt = activeUploadTransportTokens.get(requestDatacenter.datacenterId); + int datacenterUploadTransportToken = uploadTokenIt != null ? uploadTokenIt : 0; + + Integer downloadTokenIt = activeDownloadTransportTokens.get(requestDatacenter.datacenterId); + int datacenterDownloadTransportToken = downloadTokenIt != null ? downloadTokenIt : 0; + + double maxTimeout = 8.0; + + if ((request.flags & RPCRequest.RPCRequestClassGeneric) != 0) { + if (datacenterTransportToken == 0) { + continue; + } + } else if ((request.flags & RPCRequest.RPCRequestClassDownloadMedia) != 0) { + if (!haveNetwork) { + FileLog.d("tmessages", "Don't have any network connection, skipping download request"); + continue; + } + if (datacenterDownloadTransportToken == 0) { + continue; + } + maxTimeout = 40.0; + } else if ((request.flags & RPCRequest.RPCRequestClassUploadMedia) != 0) { + if (!haveNetwork) { + FileLog.d("tmessages", "Don't have any network connection, skipping upload request"); + continue; + } + if (datacenterUploadTransportToken == 0) { + continue; + } + maxTimeout = 30.0; + } + + long sessionId = 0; + if ((request.flags & RPCRequest.RPCRequestClassGeneric) != 0) { + sessionId = requestDatacenter.authSessionId; + } else if ((request.flags & RPCRequest.RPCRequestClassDownloadMedia) != 0) { + sessionId = requestDatacenter.authDownloadSessionId; + } else if ((request.flags & RPCRequest.RPCRequestClassUploadMedia) != 0 ) { + sessionId = requestDatacenter.authUploadSessionId; + } + + boolean forceThisRequest = (request.flags & requestClass) != 0 && (_datacenterId == Integer.MIN_VALUE || requestDatacenter.datacenterId == _datacenterId); + + if (request.rawRequest instanceof TLRPC.TL_get_future_salts || request.rawRequest instanceof TLRPC.TL_destroy_session) { + if (request.runningMessageId != 0) { + request.addRespondMessageId(request.runningMessageId); + } + request.runningMessageId = 0; + request.runningMessageSeqNo = 0; + request.transportChannelToken = 0; + forceThisRequest = false; + } + + if (((Math.abs(currentTime - request.runningStartTime) > maxTimeout) && (currentTime > request.runningMinStartTime || Math.abs(currentTime - request.runningMinStartTime) > 60.0)) || forceThisRequest) { + if (!forceThisRequest && request.transportChannelToken > 0) { + if ((request.flags & RPCRequest.RPCRequestClassGeneric) != 0 && datacenterTransportToken == request.transportChannelToken) { + FileLog.d("tmessages", "Request token is valid, not retrying " + request.rawRequest); + continue; + } else if ((request.flags & RPCRequest.RPCRequestClassDownloadMedia) != 0) { + if (datacenterDownloadTransportToken != 0 && request.transportChannelToken == datacenterDownloadTransportToken) { + FileLog.d("tmessages", "Request download token is valid, not retrying " + request.rawRequest); + continue; + } + } else if ((request.flags & RPCRequest.RPCRequestClassUploadMedia) != 0) { + if (datacenterUploadTransportToken != 0 && request.transportChannelToken == datacenterUploadTransportToken) { + FileLog.d("tmessages", "Request upload token is valid, not retrying " + request.rawRequest); + continue; + } + } + } + + request.retryCount++; + NetworkMessage networkMessage = new NetworkMessage(); + networkMessage.protoMessage = new TLRPC.TL_protoMessage(); + + if (request.runningMessageSeqNo == 0) { + request.runningMessageSeqNo = generateMessageSeqNo(sessionId, true); + request.runningMessageId = generateMessageId(); + } + networkMessage.protoMessage.msg_id = request.runningMessageId; + networkMessage.protoMessage.seqno = request.runningMessageSeqNo; + networkMessage.protoMessage.bytes = request.serializedLength; + networkMessage.protoMessage.body = request.rpcRequest; + networkMessage.rawRequest = request.rawRequest; + networkMessage.requestId = request.token; + + request.runningStartTime = currentTime; + + if ((request.flags & RPCRequest.RPCRequestClassGeneric) != 0) { + request.transportChannelToken = datacenterTransportToken; + addMessageToDatacenter(genericMessagesToDatacenters, requestDatacenter.datacenterId, networkMessage); + } else if ((request.flags & RPCRequest.RPCRequestClassDownloadMedia) != 0) { + request.transportChannelToken = datacenterDownloadTransportToken; + ArrayList arr = new ArrayList(); + arr.add(networkMessage); + proceedToSendingMessages(arr, sessionId, requestDatacenter.downloadConnection, false, false); + } else if ((request.flags & RPCRequest.RPCRequestClassUploadMedia) != 0) { + request.transportChannelToken = datacenterUploadTransportToken; + ArrayList arr = new ArrayList(); + arr.add(networkMessage); + proceedToSendingMessages(arr, sessionId, requestDatacenter.uploadConnection, false, false); + } + } + } + + boolean updatingState = MessagesController.Instance.updatingState; + + if (activeTransportTokens.get(currentDatacenterId) != null) { + if (!updatingState) { + Datacenter currentDatacenter = datacenterWithId(currentDatacenterId); + + for (Long it : sessionsToDestroy) { + if (destroyingSessions.contains(it)) { + continue; + } + if (System.currentTimeMillis() / 1000 - lastDestroySessionRequestTime > 2.0) { + lastDestroySessionRequestTime = (int)(System.currentTimeMillis() / 1000); + TLRPC.TL_destroy_session destroySession = new TLRPC.TL_destroy_session(); + destroySession.session_id = it; + destroyingSessions.add(it); + + NetworkMessage networkMessage = new NetworkMessage(); + networkMessage.protoMessage = wrapMessage(destroySession, currentDatacenter.authSessionId, false); + if (networkMessage.protoMessage != null) { + addMessageToDatacenter(genericMessagesToDatacenters, currentDatacenter.datacenterId, networkMessage); + } + } + } + } + } + + int genericRunningRequestCount = 0; + int uploadRunningRequestCount = 0; + int downloadRunningRequestCount = 0; + + for (RPCRequest request : runningRequests) { + if ((request.flags & RPCRequest.RPCRequestClassGeneric) != 0) { + genericRunningRequestCount++; + } else if ((request.flags & RPCRequest.RPCRequestClassUploadMedia) != 0) { + uploadRunningRequestCount++; + } else if ((request.flags & RPCRequest.RPCRequestClassDownloadMedia) != 0) { + downloadRunningRequestCount++; + } + } + + for (int i = 0; i < requestQueue.size(); i++) { + RPCRequest request = requestQueue.get(i); + if (request.cancelled) { + requestQueue.remove(i); + i--; + continue; + } + + if (updatingDcSettings && datacenters.size() > 1 && request.rawRequest instanceof TLRPC.TL_help_getConfig) { + if (updatingDcStartTime < currentTime - 60) { + updatingDcStartTime = currentTime; + ArrayList allDc = new ArrayList(datacenters.values()); + for (int a = 0; a < allDc.size(); a++) { + Datacenter dc = allDc.get(a); + if (dc.datacenterId == request.runningDatacenterId) { + allDc.remove(a); + break; + } + } + Datacenter newDc = allDc.get(Math.abs(MessagesController.random.nextInt()) % allDc.size()); + request.runningDatacenterId = newDc.datacenterId; + } + } + + int datacenterId = request.runningDatacenterId; + if (datacenterId == DEFAULT_DATACENTER_ID) { + if (movingToDatacenterId != DEFAULT_DATACENTER_ID && (request.flags & RPCRequest.RPCRequestClassEnableUnauthorized) == 0) { + continue; + } + datacenterId = currentDatacenterId; + } + + Datacenter requestDatacenter = datacenterWithId(datacenterId); + if (requestDatacenter == null) { + unknownDatacenterIds.add(datacenterId); + continue; + } else if (requestDatacenter.authKey == null) { + neededDatacenterIds.add(datacenterId); + continue; + } else if (!requestDatacenter.authorized && request.runningDatacenterId != DEFAULT_DATACENTER_ID && request.runningDatacenterId != currentDatacenterId && (request.flags & RPCRequest.RPCRequestClassEnableUnauthorized) == 0) { + unauthorizedDatacenterIds.add(datacenterId); + continue; + } + + if ((request.flags & RPCRequest.RPCRequestClassGeneric) != 0 && activeTransportTokens.get(requestDatacenter.datacenterId) == null) { + continue; + } + + if (updatingState && (request.rawRequest instanceof TLRPC.TL_account_updateStatus || request.rawRequest instanceof TLRPC.TL_account_registerDevice)) { + continue; + } + + if (request.requiresCompletion) { + if ((request.flags & RPCRequest.RPCRequestClassGeneric) != 0) { + if (genericRunningRequestCount >= 60) + continue; + + genericRunningRequestCount++; + + Integer tokenIt = activeTransportTokens.get(requestDatacenter.datacenterId); + request.transportChannelToken = tokenIt != null ? tokenIt : 0; + } else if ((request.flags & RPCRequest.RPCRequestClassUploadMedia) != 0) { + if (uploadRunningRequestCount >= 20) + continue; + + if (!haveNetwork) { + FileLog.d("tmessages", "Don't have any network connection, skipping upload request"); + continue; + } + + if (uploadRunningRequestCount >= 5) { + continue; + } + + Integer uploadTokenIt = activeUploadTransportTokens.get(requestDatacenter.datacenterId); + request.transportChannelToken = uploadTokenIt != null ? uploadTokenIt : 0; + + uploadRunningRequestCount++; + } else if ((request.flags & RPCRequest.RPCRequestClassDownloadMedia) != 0) { + if (!haveNetwork) { + FileLog.d("tmessages", "Don't have any network connection, skipping download request"); + continue; + } + + if (downloadRunningRequestCount >= 5) { + continue; + } + + Integer downloadTokenIt = activeDownloadTransportTokens.get(requestDatacenter.datacenterId); + request.transportChannelToken = downloadTokenIt != null ? downloadTokenIt : 0; + + downloadRunningRequestCount++; + } + } + + long messageId = generateMessageId(); + + SerializedData os = new SerializedData(); + request.rpcRequest.serializeToStream(os); + int requestLength = os.length(); + + if (requestLength != 0) { + long sessionId = 0; + if ((request.flags & RPCRequest.RPCRequestClassGeneric) != 0) { + sessionId = requestDatacenter.authSessionId; + } else if ((request.flags & RPCRequest.RPCRequestClassDownloadMedia) != 0) { + sessionId = requestDatacenter.authDownloadSessionId; + } else if ((request.flags & RPCRequest.RPCRequestClassUploadMedia) != 0) { + sessionId = requestDatacenter.authUploadSessionId; + } + + if ((request.flags & RPCRequest.RPCRequestClassCanCompress) != 0) { + try { + byte[] data = Utilities.compress(os.toByteArray()); + if (data.length < requestLength) { + TLRPC.TL_gzip_packed packed = new TLRPC.TL_gzip_packed(); + packed.packed_data = data; + request.rpcRequest = packed; + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + + NetworkMessage networkMessage = new NetworkMessage(); + networkMessage.protoMessage = new TLRPC.TL_protoMessage(); + networkMessage.protoMessage.msg_id = messageId; + networkMessage.protoMessage.seqno = generateMessageSeqNo(sessionId, true); + networkMessage.protoMessage.bytes = requestLength; + networkMessage.protoMessage.body = request.rpcRequest; + networkMessage.rawRequest = request.rawRequest; + networkMessage.requestId = request.token; + + request.runningMessageId = messageId; + request.runningMessageSeqNo = networkMessage.protoMessage.seqno; + request.serializedLength = requestLength; + request.runningStartTime = (int)(System.currentTimeMillis() / 1000); + if (request.requiresCompletion) { + runningRequests.add(request); + } + + if ((request.flags & RPCRequest.RPCRequestClassGeneric) != 0) { + addMessageToDatacenter(genericMessagesToDatacenters, requestDatacenter.datacenterId, networkMessage); + } else if ((request.flags & RPCRequest.RPCRequestClassDownloadMedia) != 0) { + ArrayList arr = new ArrayList(); + arr.add(networkMessage); + proceedToSendingMessages(arr, sessionId, requestDatacenter.downloadConnection, false, false); + } else if ((request.flags & RPCRequest.RPCRequestClassUploadMedia) != 0) { + ArrayList arr = new ArrayList(); + arr.add(networkMessage); + proceedToSendingMessages(arr, sessionId, requestDatacenter.uploadConnection, false, false); + } else { + FileLog.e("tmessages", "***** Error: request " + request.rawRequest + " has undefined session"); + } + } else { + FileLog.e("tmessages", "***** Couldn't serialize " + request.rawRequest); + } + + requestQueue.remove(i); + i--; + } + + for (Datacenter datacenter : datacenters.values()) { + if (genericMessagesToDatacenters.get(datacenter.datacenterId) == null && datacenter.connection != null && datacenter.connection.channelToken != 0) { + ArrayList arr = messagesIdsForConfirmation.get(datacenter.authSessionId); + if (arr != null && arr.size() != 0) { + genericMessagesToDatacenters.put(datacenter.datacenterId, new ArrayList()); + } + } + } + + for (int iter : genericMessagesToDatacenters.keySet()) { + Datacenter datacenter = datacenterWithId(iter); + if (datacenter != null) { + boolean scannedPreviousRequests = false; + long lastSendMessageRpcId = 0; + + boolean hasSendMessage = false; + ArrayList arr = genericMessagesToDatacenters.get(iter); + for (NetworkMessage networkMessage : arr) { + TLRPC.TL_protoMessage message = networkMessage.protoMessage; + + Object rawRequest = networkMessage.rawRequest; + + if (rawRequest != null && (rawRequest instanceof TLRPC.TL_messages_sendMessage || + rawRequest instanceof TLRPC.TL_messages_sendMedia || + rawRequest instanceof TLRPC.TL_messages_forwardMessages || + rawRequest instanceof TLRPC.TL_messages_sendEncrypted)) { + + if (rawRequest instanceof TLRPC.TL_messages_sendMessage) { + hasSendMessage = true; + } + + if (!scannedPreviousRequests) { + scannedPreviousRequests = true; + + ArrayList currentRequests = new ArrayList(); + for (NetworkMessage currentNetworkMessage : arr) { + TLRPC.TL_protoMessage currentMessage = currentNetworkMessage.protoMessage; + + Object currentRawRequest = currentNetworkMessage.rawRequest; + + if (currentRawRequest instanceof TLRPC.TL_messages_sendMessage || + currentRawRequest instanceof TLRPC.TL_messages_sendMedia || + currentRawRequest instanceof TLRPC.TL_messages_forwardMessages || + currentRawRequest instanceof TLRPC.TL_messages_sendEncrypted) { + currentRequests.add(currentMessage.msg_id); + } + } + + long maxRequestId = 0; + for (RPCRequest request : runningRequests) { + if (request.rawRequest instanceof TLRPC.TL_messages_sendMessage || + request.rawRequest instanceof TLRPC.TL_messages_sendMedia || + request.rawRequest instanceof TLRPC.TL_messages_forwardMessages || + request.rawRequest instanceof TLRPC.TL_messages_sendEncrypted) { + if (!currentRequests.contains(request.runningMessageId)) { + maxRequestId = Math.max(maxRequestId, request.runningMessageId); + } + } + } + + lastSendMessageRpcId = maxRequestId; + } + + if (lastSendMessageRpcId != 0 && lastSendMessageRpcId != message.msg_id) { + TLRPC.TL_invokeAfterMsg invokeAfterMsg = new TLRPC.TL_invokeAfterMsg(); + invokeAfterMsg.msg_id = lastSendMessageRpcId; + invokeAfterMsg.query = message.body; + + message.body = invokeAfterMsg; + message.bytes = message.bytes + 4 + 8; + } + + lastSendMessageRpcId = message.msg_id; + } + } + + if (datacenter.connection == null) { + datacenter.connection = new TcpConnection(datacenter.datacenterId); + datacenter.connection.delegate = this; + datacenter.connection.transportRequestClass = RPCRequest.RPCRequestClassGeneric; + } + + proceedToSendingMessages(arr, datacenter.authSessionId, datacenter.connection, hasSendMessage, arr.size() != 0); + } + } + + if ((requestClass & RPCRequest.RPCRequestClassGeneric) != 0) { + if (_datacenterId == Integer.MIN_VALUE) { + for (Datacenter datacenter : datacenters.values()) { + ArrayList messagesIt = genericMessagesToDatacenters.get(datacenter.datacenterId); + if (messagesIt == null || messagesIt.size() == 0) { + generatePing(datacenter); + } + } + } else { + ArrayList messagesIt = genericMessagesToDatacenters.get(_datacenterId); + if (messagesIt == null || messagesIt.size() == 0) { + generatePing(); + } + } + } + + if (!unknownDatacenterIds.isEmpty() && !updatingDcSettings) { + updateDcSettings(); + } + + for (int num : neededDatacenterIds) { + if (num != movingToDatacenterId) { + boolean notFound = true; + for (Action actor : actionQueue) { + if (actor instanceof HandshakeAction) { + HandshakeAction eactor = (HandshakeAction)actor; + if (eactor.datacenter.datacenterId == num) { + notFound = false; + break; + } + } + } + if (notFound) { + HandshakeAction actor = new HandshakeAction(datacenterWithId(num)); + actor.delegate = this; + dequeueActor(actor, true); + } + } + } + + for (int num : unauthorizedDatacenterIds) { + if (num != currentDatacenterId && num != movingToDatacenterId && UserConfig.clientUserId != 0) { + boolean notFound = true; + for (Action actor : actionQueue) { + if (actor instanceof ExportAuthorizationAction) { + ExportAuthorizationAction eactor = (ExportAuthorizationAction)actor; + if (eactor.datacenter.datacenterId == num) { + notFound = false; + break; + } + } + } + if (notFound) { + ExportAuthorizationAction actor = new ExportAuthorizationAction(datacenterWithId(num)); + actor.delegate = this; + dequeueActor(actor, true); + } + } + } + } + + void addMessageToDatacenter(HashMap> pMap, int datacenterId, NetworkMessage message) { + ArrayList arr = pMap.get(datacenterId); + if (arr == null) { + arr = new ArrayList(); + pMap.put(datacenterId, arr); + } + arr.add(message); + } + + TLRPC.TL_protoMessage wrapMessage(TLObject message, long sessionId, boolean meaningful) { + SerializedData os = new SerializedData(); + message.serializeToStream(os); + + if (os.length() != 0) { + TLRPC.TL_protoMessage protoMessage = new TLRPC.TL_protoMessage(); + protoMessage.msg_id = generateMessageId(); + protoMessage.bytes = os.length(); + protoMessage.body = message; + protoMessage.seqno = generateMessageSeqNo(sessionId, meaningful); + return protoMessage; + } else { + FileLog.e("tmessages", "***** Couldn't serialize " + message); + return null; + } + } + + void proceedToSendingMessages(ArrayList messageList, long sessionId, TcpConnection connection, boolean reportAck, boolean requestShortTimeout) { + if (sessionId == 0) { + return; + } + + ArrayList messages = new ArrayList(); + if(messageList != null) { + messages.addAll(messageList); + } + + final ArrayList arr = messagesIdsForConfirmation.get(sessionId); + if (arr != null && arr.size() != 0) { + TLRPC.TL_msgs_ack msgAck = new TLRPC.TL_msgs_ack(); + msgAck.msg_ids = new ArrayList(); + msgAck.msg_ids.addAll(arr); + + SerializedData os = new SerializedData(); + msgAck.serializeToStream(os); + + if (os.length() != 0) { + NetworkMessage networkMessage = new NetworkMessage(); + networkMessage.protoMessage = new TLRPC.TL_protoMessage(); + + networkMessage.protoMessage.msg_id = generateMessageId(); + networkMessage.protoMessage.seqno = generateMessageSeqNo(sessionId, false); + + networkMessage.protoMessage.bytes = os.length(); + networkMessage.protoMessage.body = msgAck; + + messages.add(networkMessage); + } else { + FileLog.e("tmessages", "***** Couldn't serialize "); + } + + arr.clear(); + } + + sendMessagesToTransport(messages, connection, sessionId, reportAck, requestShortTimeout); + } + + void sendMessagesToTransport(ArrayList messagesToSend, TcpConnection connection, long sessionId, boolean reportAck, boolean requestShortTimeout) { + if (messagesToSend.size() == 0) { + return; + } + + if (connection == null) { + FileLog.e("tmessages", String.format("***** Transport for session 0x%x not found", sessionId)); + return; + } + + ArrayList currentMessages = new ArrayList(); + + int currentSize = 0; + for (int a = 0; a < messagesToSend.size(); a++) { + NetworkMessage networkMessage = messagesToSend.get(a); + currentMessages.add(networkMessage); + + TLRPC.TL_protoMessage protoMessage = networkMessage.protoMessage; + + currentSize += protoMessage.bytes; + + if (currentSize >= 3 * 1024 || a == messagesToSend.size() - 1) { + ArrayList quickAckId = new ArrayList(); + byte[] transportData = createConnectionData(currentMessages, sessionId, quickAckId, connection); + + if (transportData != null) { + if (reportAck && quickAckId.size() != 0) { + ArrayList requestIds = new ArrayList(); + + for (NetworkMessage message : messagesToSend) { + if (message.requestId != 0) { + requestIds.add(message.requestId); + } + } + + if (requestIds.size() != 0) { + int ack = quickAckId.get(0); + ArrayList arr = quickAckIdToRequestIds.get(ack); + if (arr == null) { + arr = new ArrayList(); + quickAckIdToRequestIds.put(ack, arr); + } + arr.addAll(requestIds); + } + } + + connection.sendData(transportData, reportAck, requestShortTimeout); + } else { + FileLog.e("tmessages", "***** Transport data is nil"); + } + + currentSize = 0; + currentMessages.clear(); + } + } + } + + @SuppressWarnings("unused") + byte[] createConnectionData(ArrayList messages, long sessionId, ArrayList quickAckId, TcpConnection connection) { + Datacenter datacenter = datacenterWithId(connection.getDatacenterId()); + if (datacenter.authKey == null) { + return null; + } + + long messageId; + TLObject messageBody; + int messageSeqNo; + + if (messages.size() == 1) { + NetworkMessage networkMessage = messages.get(0); + TLRPC.TL_protoMessage message = networkMessage.protoMessage; + + FileLog.d("tmessages", sessionId + ":Send message " + datacenter.datacenterId + "> Send message (" + message.seqno + ", " + message.msg_id + "): " + message.body); + + long msg_time = getTimeFromMsgId(message.msg_id); + long currentTime = System.currentTimeMillis() + ((long)timeDifference) * 1000; + + if (msg_time < currentTime - 30000 || msg_time > currentTime + 25000) { + FileLog.d("tmessages", "wrap in messages continaer"); + TLRPC.TL_msg_container messageContainer = new TLRPC.TL_msg_container(); + messageContainer.messages = new ArrayList(); + messageContainer.messages.add(message); + + messageId = generateMessageId(); + messageBody = messageContainer; + messageSeqNo = generateMessageSeqNo(sessionId, false); + } else { + messageId = message.msg_id; + messageBody = message.body; + messageSeqNo = message.seqno; + } + } else { + TLRPC.TL_msg_container messageContainer = new TLRPC.TL_msg_container(); + + ArrayList containerMessages = new ArrayList(messages.size()); + + for (NetworkMessage networkMessage : messages) { + TLRPC.TL_protoMessage message = networkMessage.protoMessage; + containerMessages.add(message); + FileLog.d("tmessages", sessionId + ":DC" + datacenter.datacenterId + "> Send message (" + message.seqno + ", " + message.msg_id + "): " + message.body); + } + + messageContainer.messages = containerMessages; + + messageId = generateMessageId(); + messageBody = messageContainer; + messageSeqNo = generateMessageSeqNo(sessionId, false); + } + + SerializedData innerMessageOs = new SerializedData(); + messageBody.serializeToStream(innerMessageOs); + byte[] messageData = innerMessageOs.toByteArray(); + + SerializedData innerOs = new SerializedData(8 + 8 + 8 + 4 + 4 + messageData.length); + long serverSalt = datacenter.selectServerSalt(getCurrentTime()); + if (serverSalt == 0) { + innerOs.writeInt64(0); + } else { + innerOs.writeInt64(serverSalt); + } + innerOs.writeInt64(sessionId); + innerOs.writeInt64(messageId); + innerOs.writeInt32(messageSeqNo); + innerOs.writeInt32(messageData.length); + innerOs.writeRaw(messageData); + byte[] innerData = innerOs.toByteArray(); + + byte[] messageKeyFull = Utilities.computeSHA1(innerData); + byte[] messageKey = new byte[16]; + System.arraycopy(messageKeyFull, messageKeyFull.length - 16, messageKey, 0, 16); + + if (quickAckId != null) { + SerializedData data = new SerializedData(messageKeyFull); + quickAckId.add(data.readInt32() & 0x7fffffff); + } + + MessageKeyData keyData = Utilities.generateMessageKeyData(datacenter.authKey, messageKey, false); + + SerializedData dataForEncryption = new SerializedData(innerData.length + (innerData.length % 16)); + dataForEncryption.writeRaw(innerData); + byte[] b = new byte[1]; + while (dataForEncryption.length() % 16 != 0) { + MessagesController.random.nextBytes(b); + dataForEncryption.writeByte(b[0]); + } + + byte[] encryptedData = Utilities.aesIgeEncryption(dataForEncryption.toByteArray(), keyData.aesKey, keyData.aesIv, true, false); + + try { + SerializedData data = new SerializedData(datacenter.authKeyId.length + messageKey.length + encryptedData.length); + data.writeRaw(datacenter.authKeyId); + data.writeRaw(messageKey); + data.writeRaw(encryptedData); + + return data.toByteArray(); + } catch (Exception e) { + FileLog.e("tmessages", e); + innerData = null; + messageData = null; + System.gc(); + SerializedData data = new SerializedData(); + data.writeRaw(datacenter.authKeyId); + data.writeRaw(messageKey); + data.writeRaw(encryptedData); + + return data.toByteArray(); + } + } + + void refillSaltSet(final Datacenter datacenter) { + for (RPCRequest request : requestQueue) { + if (request.rawRequest instanceof TLRPC.TL_get_future_salts) { + return; + } + } + + for (RPCRequest request : runningRequests) { + if (request.rawRequest instanceof TLRPC.TL_get_future_salts) { + return; + } + } + + TLRPC.TL_get_future_salts getFutureSalts = new TLRPC.TL_get_future_salts(); + getFutureSalts.num = 64; + + performRpc(getFutureSalts, new RPCRequest.RPCRequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + TLRPC.TL_futuresalts res = (TLRPC.TL_futuresalts)response; + if (error == null) { + int currentTime = getCurrentTime(); + datacenter.mergeServerSalts(currentTime, res.salts); + saveSession(); + } + } + }, null, true, RPCRequest.RPCRequestClassGeneric, datacenter.datacenterId); + } + + void messagesConfirmed(final long requestMsgId) { + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + for (RPCRequest request : runningRequests) { + if (requestMsgId == request.runningMessageId) { + request.confirmed = true; + } + } + } + }); + } + + void rpcCompleted(final long requestMsgId) { + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + for (int i = 0; i < runningRequests.size(); i++) { + RPCRequest request = runningRequests.get(i); + removeRequestInClass(request.token); + if (request.respondsToMessageId(requestMsgId)) { + runningRequests.remove(i); + i--; + } + } + } + }); + } + + void processMessage(TLObject message, long messageId, int messageSeqNo, long messageSalt, TcpConnection connection, long sessionId, long innerMsgId, long containerMessageId) { + if (message == null) { + FileLog.e("tmessages", "message is null"); + return; + } + Datacenter datacenter = datacenterWithId(connection.getDatacenterId()); + + if (message instanceof TLRPC.TL_new_session_created) { + TLRPC.TL_new_session_created newSession = (TLRPC.TL_new_session_created)message; + ArrayList arr = processedSessionChanges.get(sessionId); + if (arr == null) { + arr = new ArrayList(); + processedSessionChanges.put(sessionId, arr); + } + if (!arr.contains(newSession.unique_id)) { + FileLog.d("tmessages", "New session:"); + FileLog.d("tmessages", String.format(" first message id: %d", newSession.first_msg_id)); + FileLog.d("tmessages", String.format(" server salt: %d", newSession.server_salt)); + FileLog.d("tmessages", String.format(" unique id: %d", newSession.unique_id)); + + long serverSalt = newSession.server_salt; + + ServerSalt serverSaltDesc = new ServerSalt(); + serverSaltDesc.validSince = getCurrentTime(); + serverSaltDesc.validUntil = getCurrentTime() + 30 * 60; + serverSaltDesc.value = serverSalt; + datacenter.addServerSalt(serverSaltDesc); + + for (RPCRequest request : runningRequests) { + Datacenter dcenter = datacenterWithId(request.runningDatacenterId); + if (request.runningMessageId < newSession.first_msg_id && (request.flags & connection.transportRequestClass) != 0 && dcenter != null && dcenter.datacenterId == datacenter.datacenterId) { + request.runningMessageId = 0; + request.runningMessageSeqNo = 0; + request.runningStartTime = 0; + request.runningMinStartTime = 0; + request.transportChannelToken = 0; + } + } + + saveSession(); + + if (sessionId == datacenter.authSessionId && datacenter.datacenterId == currentDatacenterId && UserConfig.clientActivated) { + MessagesController.Instance.getDifference(); + } + arr.add(newSession.unique_id); + } + } else if (message instanceof TLRPC.TL_msg_container) { + /*if (messageId != 0) { + long time = getTimeFromMsgId(messageId); + long currentTime = System.currentTimeMillis(); + timeDifference = (int)((time - currentTime) / 1000 - currentPingTime / 2.0); + }*/ + + TLRPC.TL_msg_container messageContainer = (TLRPC.TL_msg_container)message; + for (TLRPC.TL_protoMessage innerMessage : messageContainer.messages) { + long innerMessageId = innerMessage.msg_id; + if (innerMessage.seqno % 2 != 0) { + ArrayList set = messagesIdsForConfirmation.get(sessionId); + if (set == null) { + set = new ArrayList(); + messagesIdsForConfirmation.put(sessionId, set); + } + set.add(innerMessageId); + } + if (isMessageIdProcessed(sessionId, innerMessageId)) { + continue; + } + processMessage(innerMessage.body, 0, innerMessage.seqno, messageSalt, connection, sessionId, innerMessageId, messageId); + addProcessedMessageId(sessionId, innerMessageId); + } + } else if (message instanceof TLRPC.TL_pong) { + TLRPC.TL_pong pong = (TLRPC.TL_pong)message; + long pingId = pong.ping_id; + + ArrayList itemsToDelete = new ArrayList(); + for (Long pid : pingIdToDate.keySet()) { + if (pid == pingId) { + int time = pingIdToDate.get(pid); + int pingTime = (int)(System.currentTimeMillis() / 1000) - time; + + if (Math.abs(pingTime) < 10) { + currentPingTime = (pingTime + currentPingTime) / 2; + + if (messageId != 0) { + long timeMessage = getTimeFromMsgId(messageId); + long currentTime = System.currentTimeMillis(); + timeDifference = (int)((timeMessage - currentTime) / 1000 - currentPingTime / 2.0); + } + } + itemsToDelete.add(pid); + } else if (pid < pingId) { + itemsToDelete.add(pid); + } + } + for (Long pid : itemsToDelete) { + pingIdToDate.remove(pid); + } + } else if (message instanceof TLRPC.TL_futuresalts) { + TLRPC.TL_futuresalts futureSalts = (TLRPC.TL_futuresalts)message; + long requestMid = futureSalts.req_msg_id; + for (RPCRequest request : runningRequests) { + if (request.respondsToMessageId(requestMid)) { + if (request.completionBlock != null) { + request.completionBlock.run(futureSalts, null); + } + + messagesConfirmed(requestMid); + rpcCompleted(requestMid); + + break; + } + } + } else if (message instanceof TLRPC.DestroySessionRes) { + TLRPC.DestroySessionRes res = (TLRPC.DestroySessionRes)message; + ArrayList lst = new ArrayList(); + lst.addAll(sessionsToDestroy); + destroyingSessions.remove(res.session_id); + for (long session : lst) { + if (session == res.session_id) { + sessionsToDestroy.remove(session); + FileLog.d("tmessages", String.format("Destroyed session %d (%s)", res.session_id, res instanceof TLRPC.TL_destroy_session_ok ? "ok" : "not found")); + break; + } + } + } else if (message instanceof TLRPC.TL_rpc_result) { + TLRPC.TL_rpc_result resultContainer = (TLRPC.TL_rpc_result)message; + long resultMid = resultContainer.req_msg_id; + + boolean ignoreResult = false; + FileLog.d("tmessages", "object in rpc_result is " + resultContainer.result); + if (resultContainer.result instanceof TLRPC.RpcError) { + String errorMessage = ((TLRPC.RpcError)resultContainer.result).error_message; + FileLog.e("tmessages", String.format("***** RPC error %d: %s", ((TLRPC.RpcError)resultContainer.result).error_code, errorMessage)); + + int migrateToDatacenterId = DEFAULT_DATACENTER_ID; + + if (((TLRPC.RpcError)resultContainer.result).error_code == 303) { + ArrayList migrateErrors = new ArrayList(); + migrateErrors.add("NETWORK_MIGRATE_"); + migrateErrors.add("PHONE_MIGRATE_"); + migrateErrors.add("USER_MIGRATE_"); + for (String possibleError : migrateErrors) { + if (errorMessage.contains(possibleError)) { + String errorMsg = errorMessage.replace(possibleError, ""); + + Pattern pattern = Pattern.compile("[0-9]+"); + Matcher matcher = pattern.matcher(errorMsg); + if (matcher.find()) { + errorMsg = matcher.group(0); + } + + Integer val; + try { + val = Integer.parseInt(errorMsg); + } catch (Exception e) { + val = null; + } + + if (val != null) { + migrateToDatacenterId = val; + } else { + migrateToDatacenterId = DEFAULT_DATACENTER_ID; + } + } + } + } + + if (migrateToDatacenterId != DEFAULT_DATACENTER_ID) { + ignoreResult = true; + moveToDatacenter(migrateToDatacenterId); + } + } + + int retryRequestsFromDatacenter = -1; + int retryRequestsClass = 0; + + if (!ignoreResult) { + boolean found = false; + + for (RPCRequest request : runningRequests) { + if (request.respondsToMessageId(resultMid)) { + found = true; + + boolean discardResponse = false; + boolean isError = false; + if (request.completionBlock != null) { + TLRPC.TL_error implicitError = null; + if (resultContainer.result instanceof TLRPC.TL_gzip_packed) { + TLRPC.TL_gzip_packed packet = (TLRPC.TL_gzip_packed)resultContainer.result; + TLObject uncomressed = Utilities.decompress(packet.packed_data, request.rawRequest); + if (uncomressed == null) { + System.gc(); + uncomressed = Utilities.decompress(packet.packed_data, request.rawRequest); + } + if (uncomressed == null) { + throw new RuntimeException("failed to decomress responce for " + request.rawRequest); + } + resultContainer.result = uncomressed; + } + if (resultContainer.result instanceof TLRPC.RpcError) { + String errorMessage = ((TLRPC.RpcError) resultContainer.result).error_message; + FileLog.e("tmessages", String.format("***** RPC error %d: %s", ((TLRPC.RpcError) resultContainer.result).error_code, errorMessage)); + + int errorCode = ((TLRPC.RpcError) resultContainer.result).error_code; + + if (errorCode == 500 || errorCode < 0) { + if ((request.flags & RPCRequest.RPCRequestClassFailOnServerErrors) != 0) { + if (request.serverFailureCount < 1) { + discardResponse = true; + request.runningMinStartTime = request.runningStartTime + 1; + request.serverFailureCount++; + } + } else { + discardResponse = true; + request.runningMinStartTime = request.runningStartTime + 1; + request.confirmed = false; + } + } else if (errorCode == 420) { + if ((request.flags & RPCRequest.RPCRequestClassFailOnServerErrors) == 0) { + double waitTime = 2.0; + + if (errorMessage.contains("FLOOD_WAIT_")) { + String errorMsg = errorMessage.replace("FLOOD_WAIT_", ""); + + Pattern pattern = Pattern.compile("[0-9]+"); + Matcher matcher = pattern.matcher(errorMsg); + if (matcher.find()) { + errorMsg = matcher.group(0); + } + + Integer val; + try { + val = Integer.parseInt(errorMsg); + } catch (Exception e) { + val = null; + } + if (val != null) { + waitTime = val; + } + } + + waitTime = Math.min(30, waitTime); + + discardResponse = true; + request.runningMinStartTime = (int)(System.currentTimeMillis() / 1000 + waitTime); + request.confirmed = false; + } + } + + implicitError = new TLRPC.TL_error(); + implicitError.code = ((TLRPC.RpcError)resultContainer.result).error_code; + implicitError.text = ((TLRPC.RpcError)resultContainer.result).error_message; + } else if (!(resultContainer.result instanceof TLRPC.TL_error)) { + if (request.rawRequest == null || !request.rawRequest.responseClass().isAssignableFrom(resultContainer.result.getClass())) { + if (request.rawRequest == null) { + FileLog.e("tmessages", "rawRequest is null"); + } else { + FileLog.e("tmessages", "***** RPC error: invalid response class " + resultContainer.result + " (" + request.rawRequest.responseClass() + " expected)"); + } + implicitError = new TLRPC.TL_error(); + implicitError.code = -1000; + } + } + + if (!discardResponse) { + if (implicitError != null || resultContainer.result instanceof TLRPC.TL_error) { + isError = true; + request.completionBlock.run(null, implicitError != null ? implicitError : (TLRPC.TL_error) resultContainer.result); + } else { + request.completionBlock.run(resultContainer.result, null); + } + } + + if (implicitError != null && implicitError.code == 401) { + isError = true; + if (datacenter.datacenterId == currentDatacenterId || datacenter.datacenterId == movingToDatacenterId) { + if ((request.flags & RPCRequest.RPCRequestClassGeneric) != 0) { + if (UserConfig.clientActivated) { + UserConfig.clearConfig(); + Utilities.RunOnUIThread(new Runnable() { + @Override + public void run() { + NotificationCenter.Instance.postNotificationName(1234); + } + }); + } + } + } else { + datacenter.authorized = false; + saveSession(); + discardResponse = true; + if ((request.flags & RPCRequest.RPCRequestClassDownloadMedia) != 0 || (request.flags & RPCRequest.RPCRequestClassUploadMedia) != 0) { + retryRequestsFromDatacenter = datacenter.datacenterId; + retryRequestsClass = request.flags; + } + } + } + } + + if (!discardResponse) { + if (request.initRequest && !isError) { + if (datacenter.lastInitVersion != currentAppVersion) { + datacenter.lastInitVersion = currentAppVersion; + saveSession(); + FileLog.e("tmessages", "init connection completed"); + } else { + FileLog.e("tmessages", "rpc is init, but init connection already completed"); + } + } + rpcCompleted(resultMid); + } else { + request.runningMessageId = 0; + request.runningMessageSeqNo = 0; + request.transportChannelToken = 0; + } + break; + } + } + + if (!found) { + FileLog.d("tmessages", "Response received, but request wasn't found."); + rpcCompleted(resultMid); + } + + messagesConfirmed(resultMid); + } + + if (retryRequestsFromDatacenter >= 0) { + processRequestQueue(retryRequestsClass, retryRequestsFromDatacenter); + } else { + processRequestQueue(0, 0); + } + } else if (message instanceof TLRPC.TL_msgs_ack) { + + } else if (message instanceof TLRPC.TL_ping) { + + } else if (message instanceof TLRPC.TL_bad_msg_notification) { + TLRPC.TL_bad_msg_notification badMsgNotification = (TLRPC.TL_bad_msg_notification)message; + + FileLog.e("tmessages", String.format("***** Bad message: %d", badMsgNotification.error_code)); + + if (badMsgNotification.error_code == 16 || badMsgNotification.error_code == 17 || badMsgNotification.error_code == 19 || badMsgNotification.error_code == 32 || badMsgNotification.error_code == 33 || badMsgNotification.error_code == 64) { + long realId = messageId != 0 ? messageId : containerMessageId; + if (realId == 0) { + realId = innerMsgId; + } + + if (realId != 0) { + long time = getTimeFromMsgId(messageId); + long currentTime = System.currentTimeMillis(); + timeDifference = (int)((time - currentTime) / 1000 - currentPingTime / 2.0); + } + + recreateSession(datacenter.authSessionId, datacenter); + saveSession(); + + lastOutgoingMessageId = 0; + clearRequestsForRequestClass(connection.transportRequestClass, datacenter); + } + } else if (message instanceof TLRPC.TL_bad_server_salt) { + if (messageId != 0) { + long time = getTimeFromMsgId(messageId); + long currentTime = System.currentTimeMillis(); + timeDifference = (int)((time - currentTime) / 1000 - currentPingTime / 2.0); + + lastOutgoingMessageId = Math.max(messageId, lastOutgoingMessageId); + } + + datacenter.clearServerSalts(); + + ServerSalt serverSaltDesc = new ServerSalt(); + serverSaltDesc.validSince = getCurrentTime(); + serverSaltDesc.validUntil = getCurrentTime() + 30 * 60; + serverSaltDesc.value = messageSalt; + + datacenter.addServerSalt(serverSaltDesc); + saveSession(); + + refillSaltSet(datacenter); + if (datacenter.authKey != null) { + processRequestQueue(RPCRequest.RPCRequestClassTransportMask, datacenter.datacenterId); + } + } else if (message instanceof TLRPC.MsgDetailedInfo) { + TLRPC.MsgDetailedInfo detailedInfo = (TLRPC.MsgDetailedInfo)message; + + boolean requestResend = false; + + if (detailedInfo instanceof TLRPC.TL_msg_detailed_info) { + long requestMid = ((TLRPC.TL_msg_detailed_info)detailedInfo).msg_id; + for (RPCRequest request : runningRequests) { + if (request.respondsToMessageId(requestMid)) { + requestResend = true; + break; + } + } + } else { + if (!isMessageIdProcessed(sessionId, messageId)) { + requestResend = true; + } + } + + if (requestResend) { + TLRPC.TL_msg_resend_req resendReq = new TLRPC.TL_msg_resend_req(); + resendReq.msg_ids.add(detailedInfo.answer_msg_id); + + NetworkMessage networkMessage = new NetworkMessage(); + networkMessage.protoMessage = wrapMessage(resendReq, sessionId, false); + + ArrayList arr = new ArrayList(); + arr.add(networkMessage); + sendMessagesToTransport(arr, connection, sessionId, false, true); + } else { + ArrayList set = messagesIdsForConfirmation.get(sessionId); + if (set == null) { + set = new ArrayList(); + messagesIdsForConfirmation.put(sessionId, set); + } + set.add(detailedInfo.answer_msg_id); + } + } else if (message instanceof TLRPC.TL_gzip_packed) { + TLRPC.TL_gzip_packed packet = (TLRPC.TL_gzip_packed)message; + TLObject result = Utilities.decompress(packet.packed_data, getRequestWithMessageId(messageId)); + processMessage(result, messageId, messageSeqNo, messageSalt, connection, sessionId, innerMsgId, containerMessageId); + } else if (message instanceof TLRPC.Updates) { + MessagesController.Instance.processUpdates((TLRPC.Updates)message, false); + } else { + FileLog.e("tmessages", "***** Error: unknown message class " + message); + } + } + + void generatePing() { + for (Datacenter datacenter : datacenters.values()) { + if (datacenter.datacenterId == currentDatacenterId) { + generatePing(datacenter); + } + } + } + + static long nextPingId = 0; + byte[] generatePingData(Datacenter datacenter, boolean recordTime) { + long sessionId = datacenter.authSessionId; + if (sessionId == 0) { + return null; + } + + TLRPC.TL_ping ping = new TLRPC.TL_ping(); + ping.ping_id = nextPingId++; + + if (recordTime && sessionId == datacenter.authSessionId) { + pingIdToDate.put(ping.ping_id, (int)(System.currentTimeMillis() / 1000)); + } + + NetworkMessage networkMessage = new NetworkMessage(); + networkMessage.protoMessage = wrapMessage(ping, sessionId, false); + + ArrayList arr = new ArrayList(); + arr.add(networkMessage); + return createConnectionData(arr, sessionId, null, datacenter.connection); + } + + void generatePing(Datacenter datacenter) { + if (datacenter.connection == null || datacenter.connection.channelToken == 0) { + return; + } + + byte[] transportData = generatePingData(datacenter, true); + if (transportData != null) { + datacenter.connection.sendData(transportData, false, true); + } + } + + public long needsToDecodeMessageIdFromPartialData(TcpConnection connection, byte[] data) { + if (data == null) { + return -1; + } + + Datacenter datacenter = datacenters.get(connection.getDatacenterId()); + SerializedData is = new SerializedData(data); + + byte[] keyId = is.readData(8); + SerializedData keyIdData = new SerializedData(keyId); + if (keyIdData.readInt64() == 0) { + return -1; + } else { + if (datacenter.authKeyId == null || !Arrays.equals(keyId, datacenter.authKeyId)) { + FileLog.e("tmessages", "Error: invalid auth key id " + connection); + return -1; + } + + byte[] messageKey = is.readData(16); + MessageKeyData keyData = Utilities.generateMessageKeyData(datacenter.authKey, messageKey, true); + + byte[] messageData = is.readData(data.length - 24); + messageData = Utilities.aesIgeEncryption(messageData, keyData.aesKey, keyData.aesIv, false, false); + + if (messageData == null) { + return -1; + } + + SerializedData messageIs = new SerializedData(messageData); + long messageServerSalt = messageIs.readInt64(); + long messageSessionId = messageIs.readInt64(); + + if (messageSessionId != datacenter.authSessionId && messageSessionId != datacenter.authDownloadSessionId && messageSessionId != datacenter.authUploadSessionId) { + FileLog.e("tmessages", String.format("***** Error: invalid message session ID (%d instead of %d)", messageSessionId, datacenter.authSessionId)); + finishUpdatingState(connection); + return -1; + } + + long messageId = messageIs.readInt64(); + int messageSeqNo = messageIs.readInt32(); + int messageLength = messageIs.readInt32(); + + boolean[] stop = new boolean[1]; + long[] reqMsgId = new long[1]; + stop[0] = false; + reqMsgId[0] = 0; + + while (!stop[0] && reqMsgId[0] == 0) { + int signature = messageIs.readInt32(stop); + if (stop[0]) { + break; + } + findReqMsgId(messageIs, signature, reqMsgId, stop); + } + + return reqMsgId[0]; + } + } + + private void findReqMsgId(SerializedData is, int signature, long[] reqMsgId, boolean[] failed) { + if (signature == 0x73f1f8dc) { + if (is.length() < 4) { + failed[0] = true; + return; + } + int count = is.readInt32(failed); + if (failed[0]) { + return; + } + + for (int i = 0; i < count; i++) { + is.readInt64(failed); + if (failed[0]) { + return; + } + is.readInt32(failed); + if (failed[0]) { + return; + } + is.readInt32(failed); + if (failed[0]) { + return; + } + + int innerSignature = is.readInt32(failed); + if (failed[0]) { + return; + } + + findReqMsgId(is, innerSignature, reqMsgId, failed); + if (failed[0] || reqMsgId[0] != 0) { + return; + } + } + } else if (signature == 0xf35c6d01) { + long value = is.readInt64(failed); + if (failed[0]) { + return; + } + reqMsgId[0] = value; + } else if (signature == 0x62d6b459) { + is.readInt32(failed); + if (failed[0]) { + return; + } + + int count = is.readInt32(failed); + if (failed[0]) { + return; + } + + for (int i = 0; i < count; i++) { + is.readInt32(failed); + if (failed[0]) { + return; + } + } + } else if (signature == 0x347773c5) { + is.readInt64(failed); + if (failed[0]) { + return; + } + is.readInt64(failed); + } + } + + //================================================================================ + // TCPConnection delegate + //================================================================================ + + @Override + public void tcpConnectionProgressChanged(TcpConnection connection, long messageId, int currentSize, int length) { + for (RPCRequest request : runningRequests) { + if (request.respondsToMessageId(messageId)) { + if (request.progressBlock != null) { + request.progressBlock.progress(length, currentSize); + } + break; + } + } + } + + @Override + public void tcpConnectionClosed(TcpConnection connection) { + if (connection.getDatacenterId() == currentDatacenterId && (connection.transportRequestClass & RPCRequest.RPCRequestClassGeneric) != 0) { + if (isNetworkOnline()) { + connectionState = 2; + } else { + connectionState = 1; + } + if (DEBUG_VERSION) { + try { + ConnectivityManager cm = (ConnectivityManager)ApplicationLoader.applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo[] networkInfos = cm.getAllNetworkInfo(); + for (NetworkInfo info : networkInfos) { + FileLog.e("tmessages", "Network: " + info.getTypeName() + " status: " + info.getState() + " info: " + info.getExtraInfo() + " object: " + info.getDetailedState() + " other: " + info); + } + if (networkInfos.length == 0) { + FileLog.e("tmessages", "no network available"); + } + } catch (Exception e) { + FileLog.e("tmessages", "NETWORK STATE GET ERROR"); + } + } + final int stateCopy = connectionState; + Utilities.RunOnUIThread(new Runnable() { + @Override + public void run() { + NotificationCenter.Instance.postNotificationName(703, stateCopy); + } + }); + } + } + + @Override + public void tcpConnectionConnected(TcpConnection connection) { + Datacenter datacenter = datacenterWithId(connection.getDatacenterId()); + if (datacenter.authKey != null) { + processRequestQueue(connection.transportRequestClass, connection.getDatacenterId()); + } + } + + @Override + public void tcpConnectionQuiackAckReceived(TcpConnection connection, int ack) { + ArrayList arr = quickAckIdToRequestIds.get(ack); + if (arr != null) { + for (RPCRequest request : runningRequests) { + if (arr.contains(request.token)) { + if (request.quickAckBlock != null) { + request.quickAckBlock.quickAck(); + } + } + } + quickAckIdToRequestIds.remove(ack); + } + } + + private void finishUpdatingState(TcpConnection connection) { + if (connection.getDatacenterId() == currentDatacenterId && (connection.transportRequestClass & RPCRequest.RPCRequestClassGeneric) != 0) { + if (ConnectionsManager.Instance.connectionState == 3 && !MessagesController.Instance.gettingDifference && !MessagesController.Instance.gettingDifferenceAgain) { + ConnectionsManager.Instance.connectionState = 0; + final int stateCopy = ConnectionsManager.Instance.connectionState; + Utilities.RunOnUIThread(new Runnable() { + @Override + public void run() { + NotificationCenter.Instance.postNotificationName(703, stateCopy); + } + }); + } + } + } + + @Override + public void tcpConnectionReceivedData(TcpConnection connection, byte[] data) { + if (connection.getDatacenterId() == currentDatacenterId && (connection.transportRequestClass & RPCRequest.RPCRequestClassGeneric) != 0) { + if (connectionState == 1 || connectionState == 2) { + connectionState = 3; + final int stateCopy = connectionState; + Utilities.RunOnUIThread(new Runnable() { + @Override + public void run() { + NotificationCenter.Instance.postNotificationName(703, stateCopy); + } + }); + } + } + Datacenter datacenter = datacenterWithId(connection.getDatacenterId()); + + SerializedData is = new SerializedData(data); + + byte[] keyId = is.readData(8); + SerializedData keyIdData = new SerializedData(keyId); + if (keyIdData.readInt64() == 0) { + long messageId = is.readInt64(); + if (isMessageIdProcessed(0, messageId)) { + finishUpdatingState(connection); + return; + } + + int messageLength = is.readInt32(); + + int constructor = is.readInt32(); + + TLObject object = TLClassStore.Instance().TLdeserialize(is, constructor, getRequestWithMessageId(messageId)); + + processMessage(object, messageId, 0, 0, connection, 0, 0, 0); + + if (object != null) { + addProcessedMessageId(0, messageId); + } + } else { + if (datacenter.authKeyId == null || !Arrays.equals(keyId, datacenter.authKeyId)) { + FileLog.e("tmessages", "Error: invalid auth key id " + connection); + return; + } + + byte[] messageKey = is.readData(16); + MessageKeyData keyData = Utilities.generateMessageKeyData(datacenter.authKey, messageKey, true); + + byte[] messageData = is.readData(data.length - 24); + + messageData = Utilities.aesIgeEncryption(messageData, keyData.aesKey, keyData.aesIv, false, false); + if (messageData == null) { + FileLog.e("tmessages", "Error: can't decrypt message data " + connection); + return; + } + + SerializedData messageIs = new SerializedData(messageData); + long messageServerSalt = messageIs.readInt64(); + long messageSessionId = messageIs.readInt64(); + + if (messageSessionId != datacenter.authSessionId && messageSessionId != datacenter.authDownloadSessionId && messageSessionId != datacenter.authUploadSessionId) { + FileLog.e("tmessages", String.format("***** Error: invalid message session ID (%d instead of %d)", messageSessionId, datacenter.authSessionId)); + finishUpdatingState(connection); + return; + } + + boolean doNotProcess = false; + + long messageId = messageIs.readInt64(); + int messageSeqNo = messageIs.readInt32(); + int messageLength = messageIs.readInt32(); + + if (isMessageIdProcessed(messageSessionId, messageId)) { + doNotProcess = true; + } + + if (messageSeqNo % 2 != 0) { + ArrayList set = messagesIdsForConfirmation.get(messageSessionId); + if (set == null) { + set = new ArrayList(); + messagesIdsForConfirmation.put(messageSessionId, set); + } + set.add(messageId); + } + + byte[] realMessageKeyFull = Utilities.computeSHA1(messageData, 0, Math.min(messageLength + 32, messageData.length)); + if (realMessageKeyFull == null) { + return; + } + byte[] realMessageKey = new byte[16]; + System.arraycopy(realMessageKeyFull, realMessageKeyFull.length - 16, realMessageKey, 0, 16); + + if (!Arrays.equals(messageKey, realMessageKey)) { + FileLog.e("tmessages", "***** Error: invalid message key"); + return; + } + + if (!doNotProcess) { + int constructor = messageIs.readInt32(); + TLObject message = TLClassStore.Instance().TLdeserialize(messageIs, constructor, getRequestWithMessageId(messageId)); + + if (message == null) { + FileLog.e("tmessages", "***** Error parsing message: " + constructor); + } else { + processMessage(message, messageId, messageSeqNo, messageServerSalt, connection, messageSessionId, 0, 0); + + addProcessedMessageId(messageSessionId, messageId); + } + } else { + proceedToSendingMessages(null, messageSessionId, connection, false, false); + } + finishUpdatingState(connection); + } + } + + public TLObject getRequestWithMessageId(long msgId) { + for (RPCRequest request : runningRequests) { + if (msgId == request.runningMessageId) { + return request.rawRequest; + } + } + return null; + } + + //================================================================================ + // Move to datacenter manage + //================================================================================ + + void moveToDatacenter(final int datacenterId) { + if (movingToDatacenterId == datacenterId) { + return; + } + movingToDatacenterId = datacenterId; + + Datacenter currentDatacenter = datacenterWithId(currentDatacenterId); + clearRequestsForRequestClass(RPCRequest.RPCRequestClassGeneric, currentDatacenter); + clearRequestsForRequestClass(RPCRequest.RPCRequestClassDownloadMedia, currentDatacenter); + clearRequestsForRequestClass(RPCRequest.RPCRequestClassUploadMedia, currentDatacenter); + + if (UserConfig.clientUserId != 0) { + TLRPC.TL_auth_exportAuthorization exportAuthorization = new TLRPC.TL_auth_exportAuthorization(); + exportAuthorization.dc_id = datacenterId; + + performRpc(exportAuthorization, new RPCRequest.RPCRequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + if (error == null) { + movingAuthorization = (TLRPC.TL_auth_exportedAuthorization)response; + authorizeOnMovingDatacenter(); + } else { + Utilities.globalQueue.postRunnable(new Runnable() { + @Override + public void run() { + moveToDatacenter(datacenterId); + } + }, 1000, false); + } + } + }, null, true, RPCRequest.RPCRequestClassGeneric, currentDatacenterId); + } else { + authorizeOnMovingDatacenter(); + } + } + + void authorizeOnMovingDatacenter() { + Datacenter datacenter = datacenterWithId(movingToDatacenterId); + if (datacenter == null) { + if (!updatingDcSettings) { + updateDcSettings(); + } + return; + } + + recreateSession(datacenter.authSessionId, datacenter); + + if (datacenter.authKey == null) { + datacenter.clearServerSalts(); + HandshakeAction actor = new HandshakeAction(datacenter); + actor.delegate = this; + dequeueActor(actor, true); + } + + if (movingAuthorization != null) { + TLRPC.TL_auth_importAuthorization importAuthorization = new TLRPC.TL_auth_importAuthorization(); + importAuthorization.id = UserConfig.clientUserId; + importAuthorization.bytes = movingAuthorization.bytes; + performRpc(importAuthorization, new RPCRequest.RPCRequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + movingAuthorization = null; + if (error == null) { + authorizedOnMovingDatacenter(); + } else { + moveToDatacenter(movingToDatacenterId); + } + } + }, null, true, RPCRequest.RPCRequestClassGeneric, datacenter.datacenterId); + } else { + authorizedOnMovingDatacenter(); + } + } + + void authorizedOnMovingDatacenter() { + Datacenter datacenter = datacenterWithId(currentDatacenterId); + if (datacenter != null && datacenter.connection != null) { + datacenter.connection.suspendConnection(true); + } + movingAuthorization = null; + currentDatacenterId = movingToDatacenterId; + movingToDatacenterId = DEFAULT_DATACENTER_ID; + saveSession(); + processRequestQueue(0, 0); + } + + //================================================================================ + // Actors manage + //================================================================================ + + public void dequeueActor(final Action actor, final boolean execute) { + if (actionQueue.size() == 0 || execute) { + actor.execute(null); + } + actionQueue.add(actor); + } + + public void cancelActor(final Action actor) { + if (actor != null) { + actionQueue.remove(actor); + } + } + + @Override + public void ActionDidFinishExecution(final Action action, HashMap params) { + if (action instanceof HandshakeAction) { + HandshakeAction eactor = (HandshakeAction)action; + eactor.datacenter.connection.delegate = this; + saveSession(); + + if (eactor.datacenter.datacenterId == currentDatacenterId || eactor.datacenter.datacenterId == movingToDatacenterId) { + timeDifference = (Integer)params.get("timeDifference"); + + recreateSession(eactor.datacenter.authSessionId, eactor.datacenter); + } + processRequestQueue(RPCRequest.RPCRequestClassTransportMask, eactor.datacenter.datacenterId); + } else if (action instanceof ExportAuthorizationAction) { + ExportAuthorizationAction eactor = (ExportAuthorizationAction)action; + + Datacenter datacenter = eactor.datacenter; + datacenter.authorized = true; + saveSession(); + processRequestQueue(RPCRequest.RPCRequestClassTransportMask, datacenter.datacenterId); + } + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + actionQueue.remove(action); + action.delegate = null; + } + }); + } + + @Override + public void ActionDidFailExecution(final Action action) { + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + actionQueue.remove(action); + action.delegate = null; + } + }); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ContactsController.java b/TMessagesProj/src/main/java/org/telegram/messenger/ContactsController.java index cd6a66eca..85b649bf8 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ContactsController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ContactsController.java @@ -183,105 +183,110 @@ public class ContactsController { private HashMap readContactsFromPhoneBook() { HashMap contactsMap = new HashMap(); - ContentResolver cr = ApplicationLoader.applicationContext.getContentResolver(); - String ids = ""; - Cursor pCur = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, projectioPhones, null, null, null); - if (pCur != null) { - if (pCur.getCount() > 0) { + try { + ContentResolver cr = ApplicationLoader.applicationContext.getContentResolver(); + String ids = ""; + Cursor pCur = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, projectioPhones, null, null, null); + if (pCur != null) { + if (pCur.getCount() > 0) { + while (pCur.moveToNext()) { + String number = pCur.getString(1); + if (number == null || number.length() == 0) { + continue; + } + number = PhoneFormat.stripExceptNumbers(number); + if (number.length() == 0) { + continue; + } + Integer id = pCur.getInt(0); + if (ids.length() != 0) { + ids += ","; + } + ids += id; + + int type = pCur.getInt(2); + Contact contact = contactsMap.get(id); + if (contact == null) { + contact = new Contact(); + contact.first_name = ""; + contact.last_name = ""; + contact.id = id; + contactsMap.put(id, contact); + } + + boolean addNumber = true; + if (number.length() > 8) { + String shortNumber = number.substring(number.length() - 8); + if (contact.shortPhones.contains(shortNumber)) { + addNumber = false; + } else { + contact.shortPhones.add(shortNumber); + } + } else { + if (contact.shortPhones.contains(number)) { + addNumber = false; + } else { + contact.shortPhones.add(number); + } + } + if (addNumber) { + contact.phones.add(number); + contact.phoneDeleted.add(0); + } + + if (type == ContactsContract.CommonDataKinds.Phone.TYPE_CUSTOM) { + contact.phoneTypes.add(pCur.getString(3)); + } else if (type == ContactsContract.CommonDataKinds.Phone.TYPE_HOME) { + contact.phoneTypes.add(ApplicationLoader.applicationContext.getString(R.string.PhoneHome)); + } else if (type == ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE) { + contact.phoneTypes.add(ApplicationLoader.applicationContext.getString(R.string.PhoneMobile)); + } else if (type == ContactsContract.CommonDataKinds.Phone.TYPE_WORK) { + contact.phoneTypes.add(ApplicationLoader.applicationContext.getString(R.string.PhoneWork)); + } else if (type == ContactsContract.CommonDataKinds.Phone.TYPE_MAIN) { + contact.phoneTypes.add(ApplicationLoader.applicationContext.getString(R.string.PhoneMain)); + } else { + contact.phoneTypes.add(ApplicationLoader.applicationContext.getString(R.string.PhoneOther)); + } + } + } + pCur.close(); + } + + pCur = cr.query(ContactsContract.Data.CONTENT_URI, projectionNames, ContactsContract.CommonDataKinds.StructuredName.CONTACT_ID + " IN (" + ids + ") AND " + ContactsContract.Data.MIMETYPE + " = '" + ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE + "'", null, null); + if (pCur != null && pCur.getCount() > 0) { while (pCur.moveToNext()) { - String number = pCur.getString(1); - if (number == null || number.length() == 0) { - continue; - } - number = PhoneFormat.stripExceptNumbers(number); - if (number.length() == 0) { - continue; - } - Integer id = pCur.getInt(0); - if (ids.length() != 0) { - ids += ","; - } - ids += id; - - int type = pCur.getInt(2); + int id = pCur.getInt(0); + String fname = pCur.getString(1); + String sname = pCur.getString(2); + String sname2 = pCur.getString(3); + String mname = pCur.getString(4); Contact contact = contactsMap.get(id); - if (contact == null) { - contact = new Contact(); - contact.first_name = ""; - contact.last_name = ""; - contact.id = id; - contactsMap.put(id, contact); - } - - boolean addNumber = true; - if (number.length() > 8) { - String shortNumber = number.substring(number.length() - 8); - if (contact.shortPhones.contains(shortNumber)) { - addNumber = false; - } else { - contact.shortPhones.add(shortNumber); + if (contact != null) { + contact.first_name = fname; + contact.last_name = sname; + if (contact.first_name == null) { + contact.first_name = ""; } - } else { - if (contact.shortPhones.contains(number)) { - addNumber = false; - } else { - contact.shortPhones.add(number); + if (mname != null && mname.length() != 0) { + if (contact.first_name.length() != 0) { + contact.first_name += " " + mname; + } else { + contact.first_name = mname; + } + } + if (contact.last_name == null) { + contact.last_name = ""; + } + if (contact.last_name.length() == 0 && contact.first_name.length() == 0 && sname2 != null && sname2.length() != 0) { + contact.first_name = sname2; } - } - if (addNumber) { - contact.phones.add(number); - contact.phoneDeleted.add(0); - } - - if (type == ContactsContract.CommonDataKinds.Phone.TYPE_CUSTOM) { - contact.phoneTypes.add(pCur.getString(3)); - } else if (type == ContactsContract.CommonDataKinds.Phone.TYPE_HOME) { - contact.phoneTypes.add(ApplicationLoader.applicationContext.getString(R.string.PhoneHome)); - } else if (type == ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE) { - contact.phoneTypes.add(ApplicationLoader.applicationContext.getString(R.string.PhoneMobile)); - } else if (type == ContactsContract.CommonDataKinds.Phone.TYPE_WORK) { - contact.phoneTypes.add(ApplicationLoader.applicationContext.getString(R.string.PhoneWork)); - } else if (type == ContactsContract.CommonDataKinds.Phone.TYPE_MAIN) { - contact.phoneTypes.add(ApplicationLoader.applicationContext.getString(R.string.PhoneMain)); - } else { - contact.phoneTypes.add(ApplicationLoader.applicationContext.getString(R.string.PhoneOther)); } } + pCur.close(); } - pCur.close(); - } - - pCur = cr.query(ContactsContract.Data.CONTENT_URI, projectionNames, ContactsContract.CommonDataKinds.StructuredName.CONTACT_ID + " IN (" + ids + ") AND " + ContactsContract.Data.MIMETYPE + " = '" + ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE + "'", null, null); - if (pCur != null && pCur.getCount() > 0) { - while (pCur.moveToNext()) { - int id = pCur.getInt(0); - String fname = pCur.getString(1); - String sname = pCur.getString(2); - String sname2 = pCur.getString(3); - String mname = pCur.getString(4); - Contact contact = contactsMap.get(id); - if (contact != null) { - contact.first_name = fname; - contact.last_name = sname; - if (contact.first_name == null) { - contact.first_name = ""; - } - if (mname != null && mname.length() != 0) { - if (contact.first_name.length() != 0) { - contact.first_name += " " + mname; - } else { - contact.first_name = mname; - } - } - if (contact.last_name == null) { - contact.last_name = ""; - } - if (contact.last_name.length() == 0 && contact.first_name.length() == 0 && sname2 != null && sname2.length() != 0) { - contact.first_name = sname2; - } - } - } - pCur.close(); + } catch (Exception e) { + FileLog.e("tmessages", e); + contactsMap.clear(); } return contactsMap; } @@ -303,18 +308,42 @@ public class ContactsController { return ret; } - public void performSyncPhoneBook(final HashMap contactHashMap, final boolean request, final boolean first) { + public void performSyncPhoneBook(final HashMap contactHashMap, final boolean requ, final boolean first) { Utilities.globalQueue.postRunnable(new Runnable() { @Override public void run() { + boolean request = requ; + if (request && first) { + if (UserConfig.contactsHash != null && UserConfig.contactsHash.length() != 0) { + UserConfig.contactsHash = ""; + UserConfig.saveConfig(false); + request = false; + } + } + FileLog.e("tmessages", "start read contacts from phone"); final HashMap contactsMap = readContactsFromPhoneBook(); final HashMap contactsBookShort = new HashMap(); int oldCount = contactHashMap.size(); + if (ConnectionsManager.disableContactsImport) { + if (requ && first) { + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + contactsBookSPhones = contactsBookShort; + contactsBook = contactsMap; + contactsSyncInProgress = false; + contactsBookLoaded = true; + loadContacts(true); + } + }); + } + return; + } + ArrayList toImport = new ArrayList(); if (!contactHashMap.isEmpty()) { - HashMap contactsMapCopy = new HashMap(contactsMap); for (HashMap.Entry pair : contactsMap.entrySet()) { Integer id = pair.getKey(); Contact value = pair.getValue(); @@ -413,7 +442,7 @@ public class ContactsController { } }); - FileLog.e("tmessages", "done procrssing contacts"); + FileLog.e("tmessages", "done processing contacts"); if (request) { if (!toImport.isEmpty()) { @@ -426,7 +455,9 @@ public class ContactsController { public void run(TLObject response, TLRPC.TL_error error) { if (error == null) { FileLog.e("tmessages", "contacts imported"); - MessagesStorage.Instance.putCachedPhoneBook(contactsMap); + if (!contactsMap.isEmpty()) { + MessagesStorage.Instance.putCachedPhoneBook(contactsMap); + } TLRPC.TL_contacts_importedContacts res = (TLRPC.TL_contacts_importedContacts)response; MessagesStorage.Instance.putUsersAndChats(res.users, null, true, true); ArrayList cArr = new ArrayList(); @@ -462,7 +493,17 @@ public class ContactsController { }); } } else { - MessagesStorage.Instance.putCachedPhoneBook(contactsMap); + if (!contactsMap.isEmpty()) { + MessagesStorage.Instance.putCachedPhoneBook(contactsMap); + } + if (first) { + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + loadContacts(true); + } + }); + } } } }); @@ -890,6 +931,9 @@ public class ContactsController { @Override public void run() { try { + if (ConnectionsManager.disableContactsImport) { + return; + } Uri rawContactUri = ContactsContract.RawContacts.CONTENT_URI.buildUpon().appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_NAME, currentAccount.name).appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_TYPE, currentAccount.type).build(); Cursor c1 = ApplicationLoader.applicationContext.getContentResolver().query(rawContactUri, new String[]{BaseColumns._ID, ContactsContract.RawContacts.SYNC2}, null, null, null); HashMap bookContacts = new HashMap(); @@ -922,20 +966,8 @@ public class ContactsController { TLRPC.TL_contact contact = new TLRPC.TL_contact(); contact.user_id = uid; newC.add(contact); - if (!delayedContactsUpdate.isEmpty()) { - int idx = delayedContactsUpdate.indexOf(-uid); - if (idx != -1) { - delayedContactsUpdate.remove(idx); - } - } } else if (uid < 0) { contactsTD.add(-uid); - if (!delayedContactsUpdate.isEmpty()) { - int idx = delayedContactsUpdate.indexOf(-uid); - if (idx != -1) { - delayedContactsUpdate.remove(idx); - } - } } } } @@ -952,8 +984,10 @@ public class ContactsController { } if (user == null) { user = MessagesController.Instance.users.get(newContact.user_id); + } else { + MessagesController.Instance.users.putIfAbsent(user.id, user); } - if (user == null || user.phone == null && user.phone.length() == 0) { + if (user == null || user.phone == null || user.phone.length() == 0) { reloadContacts = true; continue; } @@ -989,6 +1023,8 @@ public class ContactsController { } if (user == null) { user = MessagesController.Instance.users.get(uid); + } else { + MessagesController.Instance.users.putIfAbsent(user.id, user); } if (user == null) { reloadContacts = true; @@ -1095,7 +1131,7 @@ public class ContactsController { } public long addContactToPhoneBook(TLRPC.User user) { - if (currentAccount == null || user == null || user.phone == null || user.phone.length() == 0) { + if (currentAccount == null || user == null || user.phone == null || user.phone.length() == 0 || ConnectionsManager.disableContactsImport) { return -1; } long res = -1; @@ -1146,6 +1182,9 @@ public class ContactsController { } private void deleteContactFromPhoneBook(int uid) { + if (ConnectionsManager.disableContactsImport) { + return; + } ContentResolver contentResolver = ApplicationLoader.applicationContext.getContentResolver(); synchronized (observerLock) { ignoreChanges = true; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/DispatchQueue.java b/TMessagesProj/src/main/java/org/telegram/messenger/DispatchQueue.java index d4d6ed09e..00d974daa 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/DispatchQueue.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/DispatchQueue.java @@ -42,14 +42,10 @@ public class DispatchQueue extends Thread { } public void postRunnable(Runnable runnable) { - postRunnable(runnable, 0, false); + postRunnable(runnable, 0); } - public void postRunnable(Runnable runnable, boolean inFront) { - postRunnable(runnable, 0, true); - } - - public void postRunnable(Runnable runnable, int delay, boolean inFront) { + public void postRunnable(Runnable runnable, int delay) { if (handler == null) { try { synchronized (handlerSyncObject) { @@ -62,11 +58,7 @@ public class DispatchQueue extends Thread { if (handler != null) { if (delay <= 0) { - if (inFront) { - handler.postAtFrontOfQueue(runnable); - } else { - handler.post(runnable); - } + handler.post(runnable); } else { handler.postDelayed(runnable, delay); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ExportAuthorizationAction.java b/TMessagesProj/src/main/java/org/telegram/messenger/ExportAuthorizationAction.java index 9fe4965f3..355dd8512 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ExportAuthorizationAction.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ExportAuthorizationAction.java @@ -53,7 +53,7 @@ public class ExportAuthorizationAction extends Action { public void run() { beginExport(); } - }, retryCount * 1500, false); + }, retryCount * 1500); } } } @@ -84,7 +84,7 @@ public class ExportAuthorizationAction extends Action { public void run() { beginExport(); } - }, retryCount * 1500, false); + }, retryCount * 1500); } } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoadOperation.java b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoadOperation.java index 93f2b9568..5e79153f0 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoadOperation.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoadOperation.java @@ -94,6 +94,24 @@ public class FileLoadOperation { ext = ".mp4"; } + public FileLoadOperation(TLRPC.Audio audioLocation) { + if (audioLocation instanceof TLRPC.TL_audio) { + location = new TLRPC.TL_inputAudioFileLocation(); + datacenter_id = audioLocation.dc_id; + location.id = audioLocation.id; + location.access_hash = audioLocation.access_hash; + } else if (audioLocation instanceof TLRPC.TL_audioEncrypted) { + location = new TLRPC.TL_inputEncryptedFileLocation(); + location.id = audioLocation.id; + location.access_hash = audioLocation.access_hash; + datacenter_id = audioLocation.dc_id; + iv = new byte[32]; + System.arraycopy(audioLocation.iv, 0, iv, 0, iv.length); + key = audioLocation.key; + } + ext = ".m4a"; + } + public FileLoadOperation(TLRPC.Document documentLocation) { if (documentLocation instanceof TLRPC.TL_document) { location = new TLRPC.TL_inputDocumentFileLocation(); @@ -220,14 +238,14 @@ public class FileLoadOperation { opts.inSampleSize = (int)scaleFactor; } - opts.inPreferredConfig = Bitmap.Config.RGB_565; + opts.inPreferredConfig = Bitmap.Config.ARGB_8888; opts.inDither = false; image = BitmapFactory.decodeStream(is, null, opts); is.close(); if (image == null) { - if (!dontDelete) { - cacheFileFinal.delete(); - } + //if (!dontDelete) { + // cacheFileFinal.delete(); + //} } else { if (filter != null && image != null) { float bitmapW = image.getWidth(); @@ -252,13 +270,17 @@ public class FileLoadOperation { Utilities.stageQueue.postRunnable(new Runnable() { @Override public void run() { - delegate.didFinishLoadingFile(FileLoadOperation.this); + if (image == null) { + delegate.didFailedLoadingFile(FileLoadOperation.this); + } else { + delegate.didFinishLoadingFile(FileLoadOperation.this); + } } }); } catch (Exception e) { - if (!dontDelete) { - cacheFileFinal.delete(); - } + //if (!dontDelete) { + // cacheFileFinal.delete(); + //} FileLog.e("tmessages", e); } } @@ -414,7 +436,7 @@ public class FileLoadOperation { opts.inSampleSize = (int) scaleFactor; } - opts.inPreferredConfig = Bitmap.Config.RGB_565; + opts.inPreferredConfig = Bitmap.Config.ARGB_8888; opts.inDither = false; try { if (renamed) { @@ -442,10 +464,14 @@ public class FileLoadOperation { } } - if (FileLoader.Instance.runtimeHack != null) { + if (image != null && FileLoader.Instance.runtimeHack != null) { FileLoader.Instance.runtimeHack.trackFree(image.getRowBytes() * image.getHeight()); } - delegate.didFinishLoadingFile(FileLoadOperation.this); + if (image != null) { + delegate.didFinishLoadingFile(FileLoadOperation.this); + } else { + delegate.didFailedLoadingFile(FileLoadOperation.this); + } } catch (Exception e) { FileLog.e("tmessages", e); delegate.didFailedLoadingFile(FileLoadOperation.this); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java index 1bd9f831b..1ff6dbd3b 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java @@ -391,8 +391,8 @@ public class FileLoader { }); } - public void cancelLoadFile(final TLRPC.Video video, final TLRPC.PhotoSize photo, final TLRPC.Document document) { - if (video == null && photo == null && document == null) { + public void cancelLoadFile(final TLRPC.Video video, final TLRPC.PhotoSize photo, final TLRPC.Document document, final TLRPC.Audio audio) { + if (video == null && photo == null && document == null && audio == null) { return; } Utilities.fileUploadQueue.postRunnable(new Runnable() { @@ -405,6 +405,8 @@ public class FileLoader { fileName = MessageObject.getAttachFileName(photo); } else if (document != null) { fileName = MessageObject.getAttachFileName(document); + } else if (audio != null) { + fileName = MessageObject.getAttachFileName(audio); } if (fileName == null) { return; @@ -422,7 +424,7 @@ public class FileLoader { return loadOperationPaths.containsKey(fileName); } - public void loadFile(final TLRPC.Video video, final TLRPC.PhotoSize photo, final TLRPC.Document document) { + public void loadFile(final TLRPC.Video video, final TLRPC.PhotoSize photo, final TLRPC.Document document, final TLRPC.Audio audio) { Utilities.fileUploadQueue.postRunnable(new Runnable() { @Override public void run() { @@ -433,6 +435,8 @@ public class FileLoader { fileName = MessageObject.getAttachFileName(photo); } else if (document != null) { fileName = MessageObject.getAttachFileName(document); + } else if (audio != null) { + fileName = MessageObject.getAttachFileName(audio); } if (fileName == null) { return; @@ -451,6 +455,9 @@ public class FileLoader { } else if (document != null) { operation = new FileLoadOperation(document); operation.totalBytesCount = document.size; + } else if (audio != null) { + operation = new FileLoadOperation(audio); + operation.totalBytesCount = audio.size; } final String arg1 = fileName; @@ -888,7 +895,7 @@ public class FileLoader { } void enqueueImageProcessingOperationWithImage(final Bitmap image, final String filter, final String key, final CacheImage img) { - if (image == null || key == null) { + if (key == null) { return; } @@ -907,7 +914,7 @@ public class FileLoader { @Override public void run() { img.callAndClear(image); - if (memCache.get(key) == null) { + if (image != null && memCache.get(key) == null) { memCache.put(key, image); } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/GcmBroadcastReceiver.java b/TMessagesProj/src/main/java/org/telegram/messenger/GcmBroadcastReceiver.java index e045bfc92..9196e5649 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/GcmBroadcastReceiver.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/GcmBroadcastReceiver.java @@ -9,55 +9,20 @@ package org.telegram.messenger; import android.app.Activity; -import android.content.BroadcastReceiver; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; -import android.content.SharedPreferences; -import android.os.Bundle; -import android.os.PowerManager; +import android.support.v4.content.WakefulBroadcastReceiver; -import com.google.android.gms.gcm.GoogleCloudMessaging; - -public class GcmBroadcastReceiver extends BroadcastReceiver { +public class GcmBroadcastReceiver extends WakefulBroadcastReceiver { public static final int NOTIFICATION_ID = 1; @Override public void onReceive(final Context context, final Intent intent) { FileLog.d("tmessages", "GCM received intent: " + intent); + ComponentName comp = new ComponentName(context.getPackageName(), GcmService.class.getName()); + startWakefulService(context, (intent.setComponent(comp))); setResultCode(Activity.RESULT_OK); - - if (intent.getAction().equals("com.google.android.c2dm.intent.RECEIVE")) { - PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); - final PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "lock"); - wl.acquire(); - - SharedPreferences preferences = context.getSharedPreferences("Notifications", Context.MODE_PRIVATE); - boolean globalEnabled = preferences.getBoolean("EnableAll", true); - if (!globalEnabled) { - FileLog.d("tmessages", "GCM disabled"); - return; - } - - Thread thread = new Thread(new Runnable() { - public void run() { - GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(context); - String messageType = gcm.getMessageType(intent); - ConnectionsManager.Instance.resumeNetworkMaybe(); - wl.release(); - } - }); - thread.setPriority(Thread.MAX_PRIORITY); - thread.start(); - } else if (intent.getAction().equals("com.google.android.c2dm.intent.REGISTRATION")) { - String registration = intent.getStringExtra("registration_id"); - if (intent.getStringExtra("error") != null) { - FileLog.e("tmessages", "Registration failed, should try again later."); - } else if (intent.getStringExtra("unregistered") != null) { - FileLog.e("tmessages", "unregistration done, new messages from the authorized sender will be rejected"); - } else if (registration != null) { - FileLog.e("tmessages", "registration id = " + registration); - } - } } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/GcmService.java b/TMessagesProj/src/main/java/org/telegram/messenger/GcmService.java new file mode 100644 index 000000000..c5639dbbf --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/GcmService.java @@ -0,0 +1,42 @@ +/* + * This is the source code of Telegram for Android v. 1.3.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013. + */ + +package org.telegram.messenger; + +import android.app.IntentService; +import android.content.Intent; + +public class GcmService extends IntentService { + + public GcmService() { + super("GcmService"); + } + + @Override + protected void onHandleIntent(Intent intent) { + if (intent.getAction().equals("com.google.android.c2dm.intent.RECEIVE")) { +// SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Context.MODE_PRIVATE); +// boolean globalEnabled = preferences.getBoolean("EnableAll", true); +// if (!globalEnabled) { +// FileLog.d("tmessages", "GCM disabled"); +// return; +// } + ConnectionsManager.Instance.resumeNetworkMaybe(); + } else if (intent.getAction().equals("com.google.android.c2dm.intent.REGISTRATION")) { + String registration = intent.getStringExtra("registration_id"); + if (intent.getStringExtra("error") != null) { + FileLog.e("tmessages", "Registration failed, should try again later."); + } else if (intent.getStringExtra("unregistered") != null) { + FileLog.e("tmessages", "unregistration done, new messages from the authorized sender will be rejected"); + } else if (registration != null) { + FileLog.e("tmessages", "registration id = " + registration); + } + } + GcmBroadcastReceiver.completeWakefulIntent(intent); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java index c27eecf49..9341b1759 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java @@ -53,12 +53,12 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Semaphore; public class MessagesController implements NotificationCenter.NotificationCenterDelegate { - public ConcurrentHashMap chats = new ConcurrentHashMap(100, 1.0f, 1); - public ConcurrentHashMap encryptedChats = new ConcurrentHashMap(10, 1.0f, 1); - public ConcurrentHashMap users = new ConcurrentHashMap(100, 1.0f, 1); + public ConcurrentHashMap chats = new ConcurrentHashMap(100, 1.0f, 2); + public ConcurrentHashMap encryptedChats = new ConcurrentHashMap(10, 1.0f, 2); + public ConcurrentHashMap users = new ConcurrentHashMap(100, 1.0f, 2); public ArrayList dialogs = new ArrayList(); public ArrayList dialogsServerOnly = new ArrayList(); - public ConcurrentHashMap dialogs_dict = new ConcurrentHashMap(100, 1.0f, 1); + public ConcurrentHashMap dialogs_dict = new ConcurrentHashMap(100, 1.0f, 2); public SparseArray dialogMessage = new SparseArray(); public ConcurrentHashMap> printingUsers = new ConcurrentHashMap>(100, 1.0f, 2); public HashMap printingStrings = new HashMap(); @@ -137,6 +137,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter public int type; public TLRPC.FileLocation location; public TLRPC.TL_video videoLocation; + public TLRPC.TL_audio audioLocation; public TLRPC.TL_document documentLocation; public MessageObject obj; public TLRPC.EncryptedChat encryptedChat; @@ -1476,35 +1477,39 @@ public class MessagesController implements NotificationCenter.NotificationCenter } public void sendMessage(TLRPC.User user, long peer) { - sendMessage(null, 0, 0, null, null, null, null, user, null, peer); + sendMessage(null, 0, 0, null, null, null, null, user, null, null, peer); } public void sendMessage(MessageObject message, long peer) { - sendMessage(null, 0, 0, null, null, message, null, null, null, peer); + sendMessage(null, 0, 0, null, null, message, null, null, null, null, peer); } public void sendMessage(TLRPC.TL_document document, long peer) { - sendMessage(null, 0, 0, null, null, null, null, null, document, peer); + sendMessage(null, 0, 0, null, null, null, null, null, document, null, peer); } public void sendMessage(String message, long peer) { - sendMessage(message, 0, 0, null, null, null, null, null, null, peer); + sendMessage(message, 0, 0, null, null, null, null, null, null, null, peer); } public void sendMessage(TLRPC.FileLocation location, long peer) { - sendMessage(null, 0, 0, null, null, null, location, null, null, peer); + sendMessage(null, 0, 0, null, null, null, location, null, null, null, peer); } public void sendMessage(double lat, double lon, long peer) { - sendMessage(null, lat, lon, null, null, null, null, null, null, peer); + sendMessage(null, lat, lon, null, null, null, null, null, null, null, peer); } public void sendMessage(TLRPC.TL_photo photo, long peer) { - sendMessage(null, 0, 0, photo, null, null, null, null, null, peer); + sendMessage(null, 0, 0, photo, null, null, null, null, null, null, peer); } public void sendMessage(TLRPC.TL_video video, long peer) { - sendMessage(null, 0, 0, null, video, null, null, null, null, peer); + sendMessage(null, 0, 0, null, video, null, null, null, null, null, peer); + } + + public void sendMessage(TLRPC.TL_audio audio, long peer) { + sendMessage(null, 0, 0, null, null, null, null, null, null, audio, peer); } public void sendTTLMessage(TLRPC.EncryptedChat encryptedChat) { @@ -1548,7 +1553,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter performSendEncryptedRequest(reqSend, newMsgObj, encryptedChat, null); } - private void sendMessage(String message, double lat, double lon, TLRPC.TL_photo photo, TLRPC.TL_video video, MessageObject msgObj, TLRPC.FileLocation location, TLRPC.User user, TLRPC.TL_document document, long peer) { + private void sendMessage(String message, double lat, double lon, TLRPC.TL_photo photo, TLRPC.TL_video video, MessageObject msgObj, TLRPC.FileLocation location, TLRPC.User user, TLRPC.TL_document document, TLRPC.TL_audio audio, long peer) { TLRPC.Message newMsg = null; int type = -1; if (message != null) { @@ -1622,6 +1627,13 @@ public class MessagesController implements NotificationCenter.NotificationCenter type = 7; newMsg.message = "-1"; newMsg.attachPath = document.path; + } else if (audio != null) { + newMsg = new TLRPC.TL_message(); + newMsg.media = new TLRPC.TL_messageMediaAudio(); + newMsg.media.audio = audio; + type = 8; + newMsg.message = "-1"; + newMsg.attachPath = audio.path; } if (newMsg == null) { return; @@ -1699,7 +1711,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter reqSend.media = new TLRPC.TL_decryptedMessageMediaEmpty(); performSendEncryptedRequest(reqSend, newMsgObj, encryptedChat, null); } - } else if (type == 1 || type == 2 || type == 3 || type == 5 || type == 6 || type == 7) { + } else if (type >= 1 && type <= 3 || type >= 5 && type <= 8) { if (encryptedChat == null) { TLRPC.TL_messages_sendMedia reqSend = new TLRPC.TL_messages_sendMedia(); reqSend.peer = sendToPeer; @@ -1753,6 +1765,15 @@ public class MessagesController implements NotificationCenter.NotificationCenter delayedMessage.obj = newMsgObj; delayedMessage.documentLocation = document; performSendDelayedMessage(delayedMessage); + } else if (type == 8) { + reqSend.media = new TLRPC.TL_inputMediaUploadedAudio(); + reqSend.media.duration = audio.duration; + DelayedMessage delayedMessage = new DelayedMessage(); + delayedMessage.sendRequest = reqSend; + delayedMessage.type = 3; + delayedMessage.obj = newMsgObj; + delayedMessage.audioLocation = audio; + performSendDelayedMessage(delayedMessage); } } else { TLRPC.TL_decryptedMessage reqSend = new TLRPC.TL_decryptedMessage(); @@ -1837,6 +1858,22 @@ public class MessagesController implements NotificationCenter.NotificationCenter delayedMessage.encryptedChat = encryptedChat; delayedMessage.documentLocation = document; performSendDelayedMessage(delayedMessage); + } else if (type == 8) { + reqSend.media = new TLRPC.TL_decryptedMessageMediaAudio(); + reqSend.media.iv = new byte[32]; + reqSend.media.key = new byte[32]; + random.nextBytes(reqSend.media.iv); + random.nextBytes(reqSend.media.key); + reqSend.media.duration = audio.duration; + reqSend.media.size = audio.size; + + DelayedMessage delayedMessage = new DelayedMessage(); + delayedMessage.sendEncryptedRequest = reqSend; + delayedMessage.type = 3; + delayedMessage.obj = newMsgObj; + delayedMessage.encryptedChat = encryptedChat; + delayedMessage.audioLocation = audio; + performSendDelayedMessage(delayedMessage); } } } else if (type == 4) { @@ -1852,10 +1889,10 @@ public class MessagesController implements NotificationCenter.NotificationCenter } } - private void processSendedMessage(TLRPC.Message newMsg, TLRPC.Message sendedMessage, TLRPC.EncryptedFile file, TLRPC.DecryptedMessage decryptedMessage) { - if (sendedMessage != null) { - if (sendedMessage.media instanceof TLRPC.TL_messageMediaPhoto && sendedMessage.media.photo != null && newMsg.media instanceof TLRPC.TL_messageMediaPhoto && newMsg.media.photo != null) { - for (TLRPC.PhotoSize size : sendedMessage.media.photo.sizes) { + private void processSendedMessage(TLRPC.Message newMsg, TLRPC.Message sentMessage, TLRPC.EncryptedFile file, TLRPC.DecryptedMessage decryptedMessage) { + if (sentMessage != null) { + if (sentMessage.media instanceof TLRPC.TL_messageMediaPhoto && sentMessage.media.photo != null && newMsg.media instanceof TLRPC.TL_messageMediaPhoto && newMsg.media.photo != null) { + for (TLRPC.PhotoSize size : sentMessage.media.photo.sizes) { if (size instanceof TLRPC.TL_photoSizeEmpty) { continue; } @@ -1875,11 +1912,11 @@ public class MessagesController implements NotificationCenter.NotificationCenter } } } - sendedMessage.message = newMsg.message; - sendedMessage.attachPath = newMsg.attachPath; - } else if (sendedMessage.media instanceof TLRPC.TL_messageMediaVideo && sendedMessage.media.video != null && newMsg.media instanceof TLRPC.TL_messageMediaVideo && newMsg.media.video != null) { + sentMessage.message = newMsg.message; + sentMessage.attachPath = newMsg.attachPath; + } else if (sentMessage.media instanceof TLRPC.TL_messageMediaVideo && sentMessage.media.video != null && newMsg.media instanceof TLRPC.TL_messageMediaVideo && newMsg.media.video != null) { TLRPC.PhotoSize size2 = newMsg.media.video.thumb; - TLRPC.PhotoSize size = sendedMessage.media.video.thumb; + TLRPC.PhotoSize size = sentMessage.media.video.thumb; if (size2.location != null && size.location != null && !(size instanceof TLRPC.TL_photoSizeEmpty) && !(size2 instanceof TLRPC.TL_photoSizeEmpty)) { String fileName = size2.location.volume_id + "_" + size2.location.local_id; String fileName2 = size.location.volume_id + "_" + size.location.local_id; @@ -1891,12 +1928,26 @@ public class MessagesController implements NotificationCenter.NotificationCenter boolean result = cacheFile.renameTo(cacheFile2); FileLoader.Instance.replaceImageInCache(fileName, fileName2); size2.location = size.location; - sendedMessage.message = newMsg.message; - sendedMessage.attachPath = newMsg.attachPath; + sentMessage.message = newMsg.message; + sentMessage.attachPath = newMsg.attachPath; } - } else if (sendedMessage.media instanceof TLRPC.TL_messageMediaDocument && sendedMessage.media.document != null && newMsg.media instanceof TLRPC.TL_messageMediaDocument && newMsg.media.document != null) { - sendedMessage.message = newMsg.message; - sendedMessage.attachPath = newMsg.attachPath; + } else if (sentMessage.media instanceof TLRPC.TL_messageMediaDocument && sentMessage.media.document != null && newMsg.media instanceof TLRPC.TL_messageMediaDocument && newMsg.media.document != null) { + sentMessage.message = newMsg.message; + sentMessage.attachPath = newMsg.attachPath; + } else if (sentMessage.media instanceof TLRPC.TL_messageMediaAudio && sentMessage.media.audio != null && newMsg.media instanceof TLRPC.TL_messageMediaAudio && newMsg.media.audio != null) { + sentMessage.message = newMsg.message; + sentMessage.attachPath = newMsg.attachPath; + + String fileName = newMsg.media.audio.dc_id + "_" + newMsg.media.audio.id + ".m4a"; + String fileName2 = sentMessage.media.audio.dc_id + "_" + sentMessage.media.audio.id + ".m4a"; + if (fileName.equals(fileName2)) { + return; + } + File cacheFile = new File(Utilities.getCacheDir(), fileName); + File cacheFile2 = new File(Utilities.getCacheDir(), fileName2); + cacheFile.renameTo(cacheFile2); + sentMessage.media.audio.dc_id = newMsg.media.audio.dc_id; + sentMessage.media.audio.id = newMsg.media.audio.id; } } else if (file != null) { if (newMsg.media instanceof TLRPC.TL_messageMediaPhoto && newMsg.media.photo != null) { @@ -1953,6 +2004,32 @@ public class MessagesController implements NotificationCenter.NotificationCenter newMsg.media.document.path = document.path; newMsg.media.document.thumb = document.thumb; newMsg.media.document.dc_id = file.dc_id; + ArrayList arr = new ArrayList(); + arr.add(newMsg); + MessagesStorage.Instance.putMessages(arr, false, true); + } else if (newMsg.media instanceof TLRPC.TL_messageMediaAudio && newMsg.media.audio != null) { + TLRPC.Audio audio = newMsg.media.audio; + newMsg.media.audio = new TLRPC.TL_audioEncrypted(); + newMsg.media.audio.id = file.id; + newMsg.media.audio.access_hash = file.access_hash; + newMsg.media.audio.user_id = audio.user_id; + newMsg.media.audio.date = audio.date; + newMsg.media.audio.duration = audio.duration; + newMsg.media.audio.size = file.size; + newMsg.media.audio.dc_id = file.dc_id; + newMsg.media.audio.key = decryptedMessage.media.key; + newMsg.media.audio.iv = decryptedMessage.media.iv; + newMsg.media.audio.path = audio.path; + + String fileName = audio.dc_id + "_" + audio.id + ".m4a"; + String fileName2 = newMsg.media.audio.dc_id + "_" + newMsg.media.audio.id + ".m4a"; + if (fileName.equals(fileName2)) { + return; + } + File cacheFile = new File(Utilities.getCacheDir(), fileName); + File cacheFile2 = new File(Utilities.getCacheDir(), fileName2); + cacheFile.renameTo(cacheFile2); + ArrayList arr = new ArrayList(); arr.add(newMsg); MessagesStorage.Instance.putMessages(arr, false, true); @@ -2210,6 +2287,14 @@ public class MessagesController implements NotificationCenter.NotificationCenter } else { FileLoader.Instance.uploadFile(location, message.sendEncryptedRequest.media.key, message.sendEncryptedRequest.media.iv); } + } else if (message.type == 3) { + String location = message.audioLocation.path; + delayedMessages.put(location, message); + if (message.sendRequest != null) { + FileLoader.Instance.uploadFile(location, null, null); + } else { + FileLoader.Instance.uploadFile(location, message.sendEncryptedRequest.media.key, message.sendEncryptedRequest.media.iv); + } } } }); @@ -2304,15 +2389,12 @@ public class MessagesController implements NotificationCenter.NotificationCenter } else if (message.type == 2) { message.sendRequest.media.file = file; performSendMessageRequest(message.sendRequest, message.obj); + } else if (message.type == 3) { + message.sendRequest.media.file = file; + performSendMessageRequest(message.sendRequest, message.obj); } } else if (encryptedFile != null) { - if (message.type == 0) { - performSendEncryptedRequest(message.sendEncryptedRequest, message.obj, message.encryptedChat, encryptedFile); - } else if (message.type == 1) { - performSendEncryptedRequest(message.sendEncryptedRequest, message.obj, message.encryptedChat, encryptedFile); - } else if (message.type == 2) { - performSendEncryptedRequest(message.sendEncryptedRequest, message.obj, message.encryptedChat, encryptedFile); - } + performSendEncryptedRequest(message.sendEncryptedRequest, message.obj, message.encryptedChat, encryptedFile); } delayedMessages.remove(location); } @@ -2933,6 +3015,21 @@ public class MessagesController implements NotificationCenter.NotificationCenter } } + Utilities.RunOnUIThread(new Runnable() { + @Override + public void run() { + for (TLRPC.User user : res.users) { + users.put(user.id, user); + if (user.id == UserConfig.clientUserId) { + UserConfig.currentUser = user; + } + } + for (TLRPC.Chat chat : res.chats) { + chats.put(chat.id, chat); + } + } + }); + MessagesStorage.Instance.storageQueue.postRunnable(new Runnable() { @Override public void run() { @@ -3015,15 +3112,6 @@ public class MessagesController implements NotificationCenter.NotificationCenter Utilities.RunOnUIThread(new Runnable() { @Override public void run() { - for (TLRPC.User user : res.users) { - users.put(user.id, user); - if (user.id == UserConfig.clientUserId) { - UserConfig.currentUser = user; - } - } - for (TLRPC.Chat chat : res.chats) { - chats.put(chat.id, chat); - } for (HashMap.Entry> pair : messages.entrySet()) { Long key = pair.getKey(); ArrayList value = pair.getValue(); @@ -3315,7 +3403,6 @@ public class MessagesController implements NotificationCenter.NotificationCenter final ArrayList tasks = new ArrayList(); final ArrayList contactsIds = new ArrayList(); MessageObject lastMessage = null; - boolean usersAdded = false; boolean checkForUsers = true; ConcurrentHashMap usersDict; @@ -3339,6 +3426,27 @@ public class MessagesController implements NotificationCenter.NotificationCenter chatsDict = chats; } + if (usersArr != null || chatsArr != null) { + Utilities.RunOnUIThread(new Runnable() { + @Override + public void run() { + if (usersArr != null) { + for (TLRPC.User user : usersArr) { + users.put(user.id, user); + if (user.id == UserConfig.clientUserId) { + UserConfig.currentUser = user; + } + } + } + if (chatsArr != null) { + for (TLRPC.Chat chat : chatsArr) { + chats.put(chat.id, chat); + } + } + } + }); + } + int interfaceUpdateMask = 0; for (TLRPC.Update update : updates) { @@ -3629,25 +3737,10 @@ public class MessagesController implements NotificationCenter.NotificationCenter dialog.unread_count = 0; dialog.top_message = 0; dialog.last_message_date = update.date; - usersAdded = true; + Utilities.RunOnUIThread(new Runnable() { @Override public void run() { - if (usersArr != null) { - for (TLRPC.User user : usersArr) { - users.put(user.id, user); - if (user.id == UserConfig.clientUserId) { - UserConfig.currentUser = user; - } - } - } - if (chatsArr != null) { - for (TLRPC.Chat chat : chatsArr) { - chats.put(chat.id, chat); - } - } - - dialogs_dict.put(dialog.id, dialog); dialogs.add(dialog); dialogsServerOnly.clear(); @@ -3723,27 +3816,11 @@ public class MessagesController implements NotificationCenter.NotificationCenter MessagesStorage.Instance.putMessages(messagesArr, true, true); } - final boolean usersAddedConst = usersAdded; if (!messages.isEmpty() || !markAsReadMessages.isEmpty() || !deletedMessages.isEmpty() || !printChanges.isEmpty() || !chatInfoToUpdate.isEmpty() || !updatesOnMainThread.isEmpty() || !markAsReadEncrypted.isEmpty() || !contactsIds.isEmpty()) { Utilities.RunOnUIThread(new Runnable() { @Override public void run() { int updateMask = interfaceUpdateMaskFinal; - if (!usersAddedConst) { - if (usersArr != null) { - for (TLRPC.User user : usersArr) { - users.put(user.id, user); - if (user.id == UserConfig.clientUserId) { - UserConfig.currentUser = user; - } - } - } - if (chatsArr != null) { - for (TLRPC.Chat chat : chatsArr) { - chats.put(chat.id, chat); - } - } - } boolean avatarsUpdate = false; if (!updatesOnMainThread.isEmpty()) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java index e1e9cf2c3..8d7b1c673 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java @@ -334,7 +334,7 @@ public class MessagesStorage { FileLog.e("tmessages", e); } } - }, true); + }); } public void clearUserPhotos(final int uid) { @@ -967,7 +967,7 @@ public class MessagesStorage { FileLog.e("tmessages", e); } } - }, true); + }); } public void putContacts(final ArrayList contacts, final boolean deleteAll) { @@ -1102,21 +1102,21 @@ public class MessagesStorage { } cursor.dispose(); } catch (Exception e) { + contactHashMap.clear(); FileLog.e("tmessages", e); - } finally { - ContactsController.Instance.performSyncPhoneBook(contactHashMap, true, true); } + ContactsController.Instance.performSyncPhoneBook(contactHashMap, true, true); } - }, true); + }); } public void getContacts() { storageQueue.postRunnable(new Runnable() { @Override public void run() { + ArrayList contacts = new ArrayList(); + ArrayList users = new ArrayList(); try { - ArrayList contacts = new ArrayList(); - ArrayList users = new ArrayList(); SQLiteCursor cursor = database.queryFinalized("SELECT * FROM contacts WHERE 1"); String uids = ""; while (cursor.next()) { @@ -1150,12 +1150,14 @@ public class MessagesStorage { } cursor.dispose(); } - ContactsController.Instance.processLoadedContacts(contacts, users, 1); } catch (Exception e) { + contacts.clear(); + users.clear(); FileLog.e("tmessages", e); } + ContactsController.Instance.processLoadedContacts(contacts, users, 1); } - }, true); + }); } public void putMediaCount(final long uid, final int count) { @@ -1203,7 +1205,7 @@ public class MessagesStorage { FileLog.e("tmessages", e); } } - }, true); + }); } public void loadMedia(final long uid, final int offset, final int count, final int max_id, final int classGuid) { @@ -1279,7 +1281,7 @@ public class MessagesStorage { MessagesController.Instance.processLoadedMedia(res, uid, offset, count, max_id, true, classGuid); } } - }, true); + }); } public void putMedia(final long uid, final ArrayList messages) { @@ -1469,7 +1471,7 @@ public class MessagesStorage { MessagesController.Instance.processLoadedMessages(res, dialog_id, offset, count_query, max_id, true, classGuid, min_unread_id, max_unread_id, count_unread, max_unread_date, forward); } } - }, true); + }); } public void startTransaction(boolean useQueue) { @@ -2691,7 +2693,7 @@ public class MessagesStorage { MessagesController.Instance.processLoadedDialogs(dialogs, encryptedChats, 0, 0, 100, true, true); } } - }, true); + }); } public void putDialogs(final TLRPC.messages_Dialogs dialogs) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/SerializedData.java b/TMessagesProj/src/main/java/org/telegram/messenger/SerializedData.java index b7d64b164..db3abdc93 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/SerializedData.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/SerializedData.java @@ -22,12 +22,23 @@ public class SerializedData { private DataOutputStream out; private ByteArrayInputStream inbuf; private DataInputStream in; + private boolean justCalc = false; + private int len; public SerializedData() { outbuf = new ByteArrayOutputStream(); out = new DataOutputStream(outbuf); } + public SerializedData(boolean calculate) { + if (!calculate) { + outbuf = new ByteArrayOutputStream(); + out = new DataOutputStream(outbuf); + } + justCalc = calculate; + len = 0; + } + public SerializedData(int size) { outbuf = new ByteArrayOutputStream(size); out = new DataOutputStream(outbuf); @@ -50,13 +61,17 @@ public class SerializedData { in = new DataInputStream(inbuf); } - public void writeInt32(int x){ - writeInt32(x, out); + public void writeInt32(int x) { + if (!justCalc) { + writeInt32(x, out); + } else { + len += 4; + } } - protected void writeInt32(int x, DataOutputStream out){ + private void writeInt32(int x, DataOutputStream out) { try { - for(int i = 0; i < 4; i++){ + for(int i = 0; i < 4; i++) { out.write(x >> (i * 8)); } } catch(IOException gfdsgd) { @@ -65,10 +80,14 @@ public class SerializedData { } public void writeInt64(long i) { - writeInt64(i, out); + if (!justCalc) { + writeInt64(i, out); + } else { + len += 8; + } } - protected void writeInt64(long x, DataOutputStream out){ + private void writeInt64(long x, DataOutputStream out) { try { for(int i = 0; i < 8; i++){ out.write((int)(x >> (i * 8))); @@ -90,10 +109,14 @@ public class SerializedData { } public void writeBool(boolean value) { - if (value) { - writeInt32(0x997275b5); + if (!justCalc) { + if (value) { + writeInt32(0x997275b5); + } else { + writeInt32(0xbc799737); + } } else { - writeInt32(0xbc799737); + len += 4; } } @@ -143,9 +166,13 @@ public class SerializedData { return 0; } - public void writeRaw(byte[] b){ + public void writeRaw(byte[] b) { try { - out.write(b); + if (!justCalc) { + out.write(b); + } else { + len += b.length; + } } catch(Exception x) { FileLog.e("tmessages", "write raw error"); } @@ -153,7 +180,11 @@ public class SerializedData { public void writeRaw(byte[] b, int offset, int count) { try { - out.write(b, offset, count); + if (!justCalc) { + out.write(b, offset, count); + } else { + len += count; + } } catch(Exception x) { FileLog.e("tmessages", "write raw error"); } @@ -161,7 +192,11 @@ public class SerializedData { public void writeByte(int i) { try { - out.writeByte((byte)i); + if (!justCalc) { + out.writeByte((byte)i); + } else { + len += 1; + } } catch (Exception e) { FileLog.e("tmessages", "write byte error"); } @@ -169,13 +204,17 @@ public class SerializedData { public void writeByte(byte b) { try { - out.writeByte(b); + if (!justCalc) { + out.writeByte(b); + } else { + len += 1; + } } catch (Exception e) { FileLog.e("tmessages", "write byte error"); } } - public void readRaw(byte[] b){ + public void readRaw(byte[] b) { try { in.read(b); } catch(Exception x) { @@ -189,7 +228,7 @@ public class SerializedData { return arr; } - public String readString(){ + public String readString() { try { int sl = 1; int l = in.read(); @@ -233,20 +272,36 @@ public class SerializedData { return null; } - public void writeByteArray(byte[] b){ + public void writeByteArray(byte[] b) { try { if (b.length <= 253){ - out.write(b.length); + if (!justCalc) { + out.write(b.length); + } else { + len += 1; + } } else { - out.write(254); - out.write(b.length); - out.write(b.length >> 8); - out.write(b.length >> 16); + if (!justCalc) { + out.write(254); + out.write(b.length); + out.write(b.length >> 8); + out.write(b.length >> 16); + } else { + len += 4; + } + } + if (!justCalc) { + out.write(b); + } else { + len += b.length; } - out.write(b); int i = b.length <= 253 ? 1 : 4; while((b.length + i) % 4 != 0){ - out.write(0); + if (!justCalc) { + out.write(0); + } else { + len += 1; + } i++; } } catch(Exception x) { @@ -265,17 +320,33 @@ public class SerializedData { public void writeByteArray(byte[] b, int offset, int count) { try { if(count <= 253){ - out.write(count); + if (!justCalc) { + out.write(count); + } else { + len += 1; + } } else { - out.write(254); - out.write(count); - out.write(count >> 8); - out.write(count >> 16); + if (!justCalc) { + out.write(254); + out.write(count); + out.write(count >> 8); + out.write(count >> 16); + } else { + len += 4; + } + } + if (!justCalc) { + out.write(b, offset, count); + } else { + len += count; } - out.write(b, offset, count); int i = count <= 253 ? 1 : 4; while ((count + i) % 4 != 0){ - out.write(0); + if (!justCalc) { + out.write(0); + } else { + len += 1; + } i++; } } catch(Exception x) { @@ -292,7 +363,7 @@ public class SerializedData { return 0; } - public void writeDouble(double d){ + public void writeDouble(double d) { try { writeInt64(Double.doubleToRawLongBits(d)); } catch(Exception x) { @@ -301,7 +372,10 @@ public class SerializedData { } public int length() { - return isOut ? outbuf.size() : inbuf.available(); + if (!justCalc) { + return isOut ? outbuf.size() : inbuf.available(); + } + return len; } protected void set(byte[] newData) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/TcpConnection.java b/TMessagesProj/src/main/java/org/telegram/messenger/TcpConnection.java index a1484ff4c..1bdf0ff57 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/TcpConnection.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/TcpConnection.java @@ -10,6 +10,7 @@ package org.telegram.messenger; import java.io.IOException; import java.net.InetSocketAddress; +import java.net.SocketTimeoutException; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.Timer; @@ -51,6 +52,7 @@ public class TcpConnection extends PyroClientAdapter { private int willRetryConnectCount = 5; private boolean isNextPort = false; private final Integer timerSync = 1; + private boolean wasConnected; public int transportRequestClass; @@ -102,6 +104,7 @@ public class TcpConnection extends PyroClientAdapter { FileLog.d("tmessages", String.format(TcpConnection.this + " Connecting (%s:%d)", hostAddress, hostPort)); firstPacket = true; restOfTheData = null; + wasConnected = false; hasSomeDataSinceLastConnect = false; if (client != null) { client.removeListener(TcpConnection.this); @@ -113,7 +116,7 @@ public class TcpConnection extends PyroClientAdapter { if (isNextPort) { client.setTimeout(8000); } else { - client.setTimeout(35000); + client.setTimeout(15000); } selector.wakeup(); } catch (Exception e) { @@ -141,7 +144,7 @@ public class TcpConnection extends PyroClientAdapter { failedConnectionCount++; if (failedConnectionCount == 1) { if (hasSomeDataSinceLastConnect) { - willRetryConnectCount = 5; + willRetryConnectCount = 3; } else { willRetryConnectCount = 1; } @@ -217,6 +220,7 @@ public class TcpConnection extends PyroClientAdapter { firstPacket = true; restOfTheData = null; channelToken = 0; + wasConnected = false; } public void suspendConnection(boolean task) { @@ -306,7 +310,7 @@ public class TcpConnection extends PyroClientAdapter { Datacenter datacenter = ConnectionsManager.Instance.datacenterWithId(datacenterId); datacenter.storeCurrentAddressAndPortNum(); isNextPort = false; - client.setTimeout(35000); + client.setTimeout(20000); } hasSomeDataSinceLastConnect = true; @@ -407,7 +411,7 @@ public class TcpConnection extends PyroClientAdapter { } } - public void handleDisconnect(PyroClient client, Exception e) { + public void handleDisconnect(PyroClient client, Exception e, boolean timedout) { synchronized (timerSync) { if (reconnectTimer != null) { reconnectTimer.cancel(); @@ -419,9 +423,11 @@ public class TcpConnection extends PyroClientAdapter { } else { FileLog.d("tmessages", "Disconnected " + TcpConnection.this); } + boolean swirchToNextPort = wasConnected && hasSomeDataSinceLastConnect; firstPacket = true; restOfTheData = null; channelToken = 0; + wasConnected = false; if (connectionState != TcpConnectionState.TcpConnectionStageSuspended && connectionState != TcpConnectionState.TcpConnectionStageIdle) { connectionState = TcpConnectionState.TcpConnectionStageIdle; } @@ -446,7 +452,7 @@ public class TcpConnection extends PyroClientAdapter { } if (ConnectionsManager.isNetworkOnline()) { isNextPort = true; - if (failedConnectionCount > willRetryConnectCount) { + if (failedConnectionCount > willRetryConnectCount || swirchToNextPort) { Datacenter datacenter = ConnectionsManager.Instance.datacenterWithId(datacenterId); datacenter.nextAddressOrPort(); failedConnectionCount = 0; @@ -486,6 +492,7 @@ public class TcpConnection extends PyroClientAdapter { public void connectedClient(PyroClient client) { connectionState = TcpConnectionState.TcpConnectionStageConnected; channelToken = generateChannelToken(); + wasConnected = true; FileLog.d("tmessages", String.format(TcpConnection.this + " Connected (%s:%d)", hostAddress, hostPort)); if (delegate != null) { final TcpConnectionDelegate finalDelegate = delegate; @@ -500,18 +507,18 @@ public class TcpConnection extends PyroClientAdapter { @Override public void unconnectableClient(PyroClient client, Exception cause) { - handleDisconnect(client, cause); + handleDisconnect(client, cause, false); } @Override public void droppedClient(PyroClient client, IOException cause) { super.droppedClient(client, cause); - handleDisconnect(client, cause); + handleDisconnect(client, cause, (cause instanceof SocketTimeoutException)); } @Override public void disconnectedClient(PyroClient client) { - handleDisconnect(client, null); + handleDisconnect(client, null, false); } @Override @@ -527,7 +534,5 @@ public class TcpConnection extends PyroClientAdapter { @Override public void sentData(PyroClient client, int bytes) { - failedConnectionCount = 0; - FileLog.d("tmessages", TcpConnection.this + " bytes sent " + bytes); } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/UserConfig.java b/TMessagesProj/src/main/java/org/telegram/messenger/UserConfig.java index e17b045af..2d2de9144 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/UserConfig.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/UserConfig.java @@ -27,6 +27,7 @@ public class UserConfig { public static int lastSendMessageId = -210000; public static int lastLocalId = -210000; public static String contactsHash = ""; + public static String importHash = ""; private final static Integer sync = 1; public static boolean saveIncomingPhotos = false; @@ -54,6 +55,7 @@ public class UserConfig { editor.putInt("lastSendMessageId", lastSendMessageId); editor.putInt("lastLocalId", lastLocalId); editor.putString("contactsHash", contactsHash); + editor.putString("importHash", importHash); editor.putBoolean("saveIncomingPhotos", saveIncomingPhotos); if (withFile) { SerializedData data = new SerializedData(); @@ -69,6 +71,7 @@ public class UserConfig { editor.putInt("lastSendMessageId", lastSendMessageId); editor.putInt("lastLocalId", lastLocalId); editor.putString("contactsHash", contactsHash); + editor.putString("importHash", importHash); editor.putBoolean("saveIncomingPhotos", saveIncomingPhotos); editor.remove("user"); } @@ -102,7 +105,7 @@ public class UserConfig { lastSendMessageId = data.readInt32(); lastLocalId = data.readInt32(); contactsHash = data.readString(); - data.readString(); + importHash = data.readString(); saveIncomingPhotos = data.readBool(); if (currentUser.status != null) { if (currentUser.status.expires != 0) { @@ -136,6 +139,7 @@ public class UserConfig { lastSendMessageId = preferences.getInt("lastSendMessageId", -210000); lastLocalId = preferences.getInt("lastLocalId", -210000); contactsHash = preferences.getString("contactsHash", ""); + importHash = preferences.getString("importHash", ""); saveIncomingPhotos = preferences.getBoolean("saveIncomingPhotos", false); } if (lastLocalId > -210000) { @@ -160,6 +164,7 @@ public class UserConfig { lastSendMessageId = preferences.getInt("lastSendMessageId", -210000); lastLocalId = preferences.getInt("lastLocalId", -210000); contactsHash = preferences.getString("contactsHash", ""); + importHash = preferences.getString("importHash", ""); saveIncomingPhotos = preferences.getBoolean("saveIncomingPhotos", false); String user = preferences.getString("user", null); if (user != null) { @@ -185,6 +190,7 @@ public class UserConfig { currentUser = null; registeredForPush = false; contactsHash = ""; + importHash = ""; lastLocalId = -210000; lastSendMessageId = -210000; saveIncomingPhotos = false; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/Utilities.java b/TMessagesProj/src/main/java/org/telegram/messenger/Utilities.java index 3fb5ce76d..2eb549822 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/Utilities.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/Utilities.java @@ -749,9 +749,9 @@ public class Utilities { return storageDir; } - public static String getPath(final Context context, final Uri uri) { + public static String getPath(final Uri uri) { final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT; - if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) { + if (isKitKat && DocumentsContract.isDocumentUri(ApplicationLoader.applicationContext, uri)) { if (isExternalStorageDocument(uri)) { final String docId = DocumentsContract.getDocumentId(uri); final String[] split = docId.split(":"); @@ -762,7 +762,7 @@ public class Utilities { } else if (isDownloadsDocument(uri)) { final String id = DocumentsContract.getDocumentId(uri); final Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(id)); - return getDataColumn(context, contentUri, null, null); + return getDataColumn(ApplicationLoader.applicationContext, contentUri, null, null); } else if (isMediaDocument(uri)) { final String docId = DocumentsContract.getDocumentId(uri); final String[] split = docId.split(":"); @@ -782,10 +782,10 @@ public class Utilities { split[1] }; - return getDataColumn(context, contentUri, selection, selectionArgs); + return getDataColumn(ApplicationLoader.applicationContext, contentUri, selection, selectionArgs); } } else if ("content".equalsIgnoreCase(uri.getScheme())) { - return getDataColumn(context, uri, null, null); + return getDataColumn(ApplicationLoader.applicationContext, uri, null, null); } else if ("file".equalsIgnoreCase(uri.getScheme())) { return uri.getPath(); } diff --git a/TMessagesProj/src/main/java/org/telegram/objects/MessageObject.java b/TMessagesProj/src/main/java/org/telegram/objects/MessageObject.java index 95ce61df5..b86f42264 100644 --- a/TMessagesProj/src/main/java/org/telegram/objects/MessageObject.java +++ b/TMessagesProj/src/main/java/org/telegram/objects/MessageObject.java @@ -22,7 +22,6 @@ import org.telegram.ui.ApplicationLoader; import java.util.AbstractMap; import java.util.ArrayList; import java.util.Calendar; -import java.util.Date; import java.util.GregorianCalendar; public class MessageObject { @@ -303,6 +302,8 @@ public class MessageObject { return getAttachFileName(messageOwner.media.video); } else if (messageOwner.media instanceof TLRPC.TL_messageMediaDocument) { return getAttachFileName(messageOwner.media.document); + } else if (messageOwner.media instanceof TLRPC.TL_messageMediaAudio) { + return getAttachFileName(messageOwner.media.audio); } return ""; } @@ -328,6 +329,9 @@ public class MessageObject { } else if (attach instanceof TLRPC.PhotoSize) { TLRPC.PhotoSize photo = (TLRPC.PhotoSize)attach; return photo.location.volume_id + "_" + photo.location.local_id + ".jpg"; + } else if (attach instanceof TLRPC.Audio) { + TLRPC.Audio audio = (TLRPC.Audio)attach; + return audio.dc_id + "_" + audio.id + ".m4a"; } return ""; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ApplicationLoader.java b/TMessagesProj/src/main/java/org/telegram/ui/ApplicationLoader.java index 8e569011f..fde77a624 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ApplicationLoader.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ApplicationLoader.java @@ -11,6 +11,7 @@ package org.telegram.ui; import android.app.Activity; import android.app.Application; import android.content.Context; +import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; @@ -25,6 +26,7 @@ import com.google.android.gms.common.GooglePlayServicesUtil; import com.google.android.gms.gcm.GoogleCloudMessaging; import org.telegram.PhoneFormat.PhoneFormat; +import org.telegram.messenger.BackgroundService; import org.telegram.messenger.ConnectionsManager; import org.telegram.messenger.FileLog; import org.telegram.messenger.MessagesController; @@ -60,6 +62,7 @@ public class ApplicationLoader extends Application { @Override public void onCreate() { super.onCreate(); + currentLocale = Locale.getDefault(); Instance = this; @@ -130,6 +133,8 @@ public class ApplicationLoader extends Application { lastPauseTime = System.currentTimeMillis(); FileLog.e("tmessages", "start application with time " + lastPauseTime); + + startService(new Intent(this, BackgroundService.class)); } @Override diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java new file mode 100644 index 000000000..ebcd0c611 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java @@ -0,0 +1,26 @@ +/* + * This is the source code of Telegram for Android v. 1.3.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013. + */ + +package org.telegram.ui.Cells; + +import android.content.Context; +import android.util.AttributeSet; + +public class ChatMessageCell extends BaseCell { + public ChatMessageCell(Context context) { + super(context); + } + + public ChatMessageCell(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public ChatMessageCell(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatOrUserCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatOrUserCell.java index 9e23350c6..bd7e19da4 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatOrUserCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatOrUserCell.java @@ -393,7 +393,7 @@ public class ChatOrUserCell extends BaseCell { if (value == 0) { value = user.status.expires; } - onlineString = getResources().getString(R.string.LastSeen) + " " + Utilities.formatDateOnline(value); + onlineString = Utilities.formatDateOnline(value); } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogCell.java index 6adea8808..23a1a1ffe 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogCell.java @@ -394,18 +394,22 @@ public class DialogCell extends BaseCell { if (encryptedChat instanceof TLRPC.TL_encryptedChatRequested) { messageString = ApplicationLoader.applicationContext.getString(R.string.EncryptionProcessing); } else if (encryptedChat instanceof TLRPC.TL_encryptedChatWaiting) { - messageString = String.format(ApplicationLoader.applicationContext.getString(R.string.AwaitingEncryption), user.first_name); + if (user != null && user.first_name != null) { + messageString = String.format(ApplicationLoader.applicationContext.getString(R.string.AwaitingEncryption), user.first_name); + } else { + messageString = String.format(ApplicationLoader.applicationContext.getString(R.string.AwaitingEncryption), ""); + } } else if (encryptedChat instanceof TLRPC.TL_encryptedChatDiscarded) { messageString = ApplicationLoader.applicationContext.getString(R.string.EncryptionRejected); } else if (encryptedChat instanceof TLRPC.TL_encryptedChat) { if (encryptedChat.admin_id == UserConfig.clientUserId) { - if (user != null) { + if (user != null && user.first_name != null) { messageString = String.format(ApplicationLoader.applicationContext.getString(R.string.EncryptedChatStartedOutgoing), user.first_name); + } else { + messageString = String.format(ApplicationLoader.applicationContext.getString(R.string.EncryptedChatStartedOutgoing), ""); } } else { - if (user != null) { - messageString = String.format(ApplicationLoader.applicationContext.getString(R.string.EncryptedChatStartedIncoming), user.first_name); - } + messageString = ApplicationLoader.applicationContext.getString(R.string.EncryptedChatStartedIncoming); } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java index 515a1ad88..131909e7b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java @@ -22,6 +22,7 @@ import android.graphics.Rect; import android.graphics.drawable.AnimationDrawable; import android.graphics.drawable.BitmapDrawable; import android.media.MediaPlayer; +import android.media.MediaRecorder; import android.media.ThumbnailUtils; import android.net.Uri; import android.os.Bundle; @@ -37,6 +38,7 @@ import android.text.SpannableStringBuilder; import android.text.TextWatcher; import android.text.style.ClickableSpan; import android.text.style.ImageSpan; +import android.util.Log; import android.util.TypedValue; import android.view.Display; import android.view.KeyEvent; @@ -121,6 +123,7 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa private TextView emptyView; private View bottomOverlay; private TextView bottomOverlayText; + private ImageButton audioSendButton; private MessageObject selectedObject; private MessageObject forwaringMessage; private TextView secretViewStatusTextView; @@ -179,6 +182,10 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa private CharSequence lastPrintString; + private MediaRecorder audioRecorder = null; + private TLRPC.TL_audio recordingAudio = null; + private File recordingAudioFile = null; + ActionMode mActionMode = null; private ActionMode.Callback mActionModeCallback = new ActionMode.Callback() { @Override @@ -380,6 +387,7 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa View bottomOverlayChat = fragmentView.findViewById(R.id.bottom_overlay_chat); progressView = fragmentView.findViewById(R.id.progressLayout); pagedownButton = fragmentView.findViewById(R.id.pagedown_button); + audioSendButton = (ImageButton)fragmentView.findViewById(R.id.chat_audio_send_button); View progressViewInner = progressView.findViewById(R.id.progressLayoutInner); updateContactStatus(); @@ -460,7 +468,9 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa chatListView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() { @Override public boolean onItemLongClick(AdapterView adapter, View view, int position, long id) { - createMenu(view, false); + if (mActionMode == null) { + createMenu(view, false); + } return true; } }); @@ -502,8 +512,8 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa messsageEditText = (EditText)fragmentView.findViewById(R.id.chat_text_edit); sendButton = (ImageButton)fragmentView.findViewById(R.id.chat_send_button); - sendButton.setImageResource(R.drawable.send_button_states); sendButton.setEnabled(false); + sendButton.setVisibility(View.INVISIBLE); emojiButton = (ImageView)fragmentView.findViewById(R.id.chat_smile_button); if (loading && messages.isEmpty()) { @@ -568,6 +578,18 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa } }); + audioSendButton.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View view, MotionEvent motionEvent) { + if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) { + startRecording(); + } else if (motionEvent.getAction() == MotionEvent.ACTION_UP) { + stopRecording(); + } + return false; + } + }); + pagedownButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { @@ -590,6 +612,8 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa } }); + checkSendButton(); + messsageEditText.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) { @@ -602,6 +626,7 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa message = message.replaceAll("\n\n+", "\n\n"); message = message.replaceAll(" +", " "); sendButton.setEnabled(message.length() != 0); + checkSendButton(); if (message.length() != 0 && lastTypingTimeSend < System.currentTimeMillis() - 5000 && !ignoreTextChange) { int currentTime = ConnectionsManager.Instance.getCurrentTime(); @@ -722,6 +747,18 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa return fragmentView; } + private void checkSendButton() { + sendButton.setVisibility(View.VISIBLE); + audioSendButton.setVisibility(View.INVISIBLE); +// if (messsageEditText.length() > 0) { +// sendButton.setVisibility(View.VISIBLE); +// audioSendButton.setVisibility(View.INVISIBLE); +// } else { +// sendButton.setVisibility(View.INVISIBLE); +// audioSendButton.setVisibility(View.VISIBLE); +// } + } + private void sendMessage() { String message = messsageEditText.getText().toString().trim(); if (processSendingText(message)) { @@ -782,6 +819,84 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa paused = true; } + private void startRecording() { + if (audioRecorder != null) { + return; + } + + recordingAudio = new TLRPC.TL_audio(); + recordingAudio.dc_id = Integer.MIN_VALUE; + recordingAudio.id = UserConfig.lastLocalId; + recordingAudio.user_id = UserConfig.clientUserId; + UserConfig.lastLocalId--; + UserConfig.saveConfig(false); + + recordingAudioFile = new File(Utilities.getCacheDir(), MessageObject.getAttachFileName(recordingAudio)); + + audioRecorder = new MediaRecorder(); + audioRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); + audioRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4); + audioRecorder.setOutputFile(recordingAudioFile.getAbsolutePath()); + if(android.os.Build.VERSION.SDK_INT >= 10) { + audioRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC); + } else { + audioRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); + } + audioRecorder.setAudioSamplingRate(24000); + audioRecorder.setAudioChannels(1); + audioRecorder.setAudioEncodingBitRate(16000); + + try { + audioRecorder.prepare(); + audioRecorder.start(); + } catch (Exception e) { + Log.e("tmessages", "prepare() failed"); + } + } + + private void stopRecording() { + try { + audioRecorder.stop(); + audioRecorder.release(); + audioRecorder = null; + + recordingAudio.date = ConnectionsManager.Instance.getCurrentTime(); + recordingAudio.size = (int)recordingAudioFile.length(); + recordingAudio.path = recordingAudioFile.getAbsolutePath(); + int duration = 0; + + MediaPlayer player = new MediaPlayer(); + try { + player.setDataSource(recordingAudio.path); + player.prepare(); + duration = player.getDuration(); + recordingAudio.duration = duration / 1000; + } catch (Exception e) { + FileLog.e("tmessages", e); + } finally { + try { + player.release(); + player = null; + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + + if (duration > 500) { + MessagesController.Instance.sendMessage(recordingAudio, dialog_id); + } else { + recordingAudio = null; + recordingAudioFile.delete(); + recordingAudioFile = null; + } + } catch (Exception e) { + FileLog.e("tmessages", e); + recordingAudio = null; + recordingAudioFile.delete(); + recordingAudioFile = null; + } + } + private void updateSecretStatus() { if (bottomOverlay == null) { return; @@ -1125,15 +1240,8 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa if (imageUri.getScheme().contains("file")) { imageFilePath = imageUri.getPath(); } else { - ActionBarActivity inflaterActivity = parentActivity; - if (inflaterActivity == null) { - inflaterActivity = (ActionBarActivity)getActivity(); - } - if (inflaterActivity == null) { - return; - } try { - imageFilePath = Utilities.getPath(inflaterActivity, imageUri); + imageFilePath = Utilities.getPath(imageUri); } catch (Exception e) { FileLog.e("tmessages", e); } @@ -1158,15 +1266,8 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa Utilities.addMediaToGallery(currentPicturePath); currentPicturePath = null; } else { - ActionBarActivity inflaterActivity = parentActivity; - if (inflaterActivity == null) { - inflaterActivity = (ActionBarActivity)getActivity(); - } - if (inflaterActivity == null) { - return; - } try { - videoPath = Utilities.getPath(inflaterActivity, uri); + videoPath = Utilities.getPath(uri); } catch (Exception e) { FileLog.e("tmessages", e); } @@ -1477,7 +1578,7 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa } } else if (id == MessagesController.updateInterfaces) { int updateMask = (Integer)args[0]; - if ((updateMask & MessagesController.UPDATE_MASK_NAME) != 0 || (updateMask & MessagesController.UPDATE_MASK_STATUS) != 0 || (updateMask & MessagesController.UPDATE_MASK_CHAT_NAME) != 0) { + if ((updateMask & MessagesController.UPDATE_MASK_NAME) != 0 || (updateMask & MessagesController.UPDATE_MASK_STATUS) != 0 || (updateMask & MessagesController.UPDATE_MASK_CHAT_NAME) != 0 || (updateMask & MessagesController.UPDATE_MASK_CHAT_MEMBERS) != 0) { updateSubtitle(); updateOnlineCount(); } @@ -2406,6 +2507,10 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa TLRPC.TL_document document = (TLRPC.TL_document)selectedObject.messageOwner.media.document; document.path = selectedObject.messageOwner.attachPath; MessagesController.Instance.sendMessage(document, dialog_id); + } else if (selectedObject.type == 18 || selectedObject.type == 19) { + TLRPC.TL_audio audio = (TLRPC.TL_audio)selectedObject.messageOwner.media.audio; + audio.path = selectedObject.messageOwner.attachPath; + MessagesController.Instance.sendMessage(audio, dialog_id); } ArrayList arr = new ArrayList(); arr.add(selectedObject.messageOwner.id); @@ -2732,88 +2837,102 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa } else { view.setBackgroundColor(0); } - int messageType = holder.message.type; - if (!disableSelection) { - if (messageType == 2 || messageType == 4 || messageType == 6) { - holder.chatBubbleView.setBackgroundResource(R.drawable.chat_outgoing_photo_states); - } else if (messageType == 3 || messageType == 5 || messageType == 7) { - holder.chatBubbleView.setBackgroundResource(R.drawable.chat_incoming_photo_states); - } else if (messageType == 0 || messageType == 8) { - holder.messageLayout.setBackgroundResource(R.drawable.chat_outgoing_text_states); - holder.messageLayout.setPadding(Utilities.dp(11), Utilities.dp(7), Utilities.dp(18), 0); - } else if (messageType == 1 || messageType == 9) { - holder.messageLayout.setBackgroundResource(R.drawable.chat_incoming_text_states); - holder.messageLayout.setPadding(Utilities.dp(19), Utilities.dp(7), Utilities.dp(9), 0); - } else if (messageType == 12) { - holder.chatBubbleView.setBackgroundResource(R.drawable.chat_outgoing_text_states); - holder.chatBubbleView.setPadding(Utilities.dp(6), Utilities.dp(6), Utilities.dp(18), 0); - } else if (messageType == 13) { - holder.chatBubbleView.setBackgroundResource(R.drawable.chat_incoming_text_states); - holder.chatBubbleView.setPadding(Utilities.dp(15), Utilities.dp(6), Utilities.dp(9), 0); - } else if (messageType == 16) { - holder.chatBubbleView.setBackgroundResource(R.drawable.chat_outgoing_text_states); - holder.chatBubbleView.setPadding(Utilities.dp(9), Utilities.dp(9), Utilities.dp(18), 0); - } else if (messageType == 17) { - holder.chatBubbleView.setBackgroundResource(R.drawable.chat_incoming_text_states); - holder.chatBubbleView.setPadding(Utilities.dp(18), Utilities.dp(9), Utilities.dp(9), 0); - } + updateRowBackground(holder, disableSelection, selected); + } + } + } + + private void updateRowBackground(ChatListRowHolderEx holder, boolean disableSelection, boolean selected) { + int messageType = holder.message.type; + if (!disableSelection) { + if (messageType == 2 || messageType == 4 || messageType == 6) { + holder.chatBubbleView.setBackgroundResource(R.drawable.chat_outgoing_photo_states); + } else if (messageType == 3 || messageType == 5 || messageType == 7) { + holder.chatBubbleView.setBackgroundResource(R.drawable.chat_incoming_photo_states); + } else if (messageType == 0 || messageType == 8) { + holder.messageLayout.setBackgroundResource(R.drawable.chat_outgoing_text_states); + holder.messageLayout.setPadding(Utilities.dp(11), Utilities.dp(7), Utilities.dp(18), 0); + } else if (messageType == 1 || messageType == 9) { + holder.messageLayout.setBackgroundResource(R.drawable.chat_incoming_text_states); + holder.messageLayout.setPadding(Utilities.dp(19), Utilities.dp(7), Utilities.dp(9), 0); + } else if (messageType == 12) { + holder.chatBubbleView.setBackgroundResource(R.drawable.chat_outgoing_text_states); + holder.chatBubbleView.setPadding(Utilities.dp(6), Utilities.dp(6), Utilities.dp(18), 0); + } else if (messageType == 13) { + holder.chatBubbleView.setBackgroundResource(R.drawable.chat_incoming_text_states); + holder.chatBubbleView.setPadding(Utilities.dp(15), Utilities.dp(6), Utilities.dp(9), 0); + } else if (messageType == 16) { + holder.chatBubbleView.setBackgroundResource(R.drawable.chat_outgoing_text_states); + holder.chatBubbleView.setPadding(Utilities.dp(9), Utilities.dp(9), Utilities.dp(18), 0); + } else if (messageType == 17) { + holder.chatBubbleView.setBackgroundResource(R.drawable.chat_incoming_text_states); + holder.chatBubbleView.setPadding(Utilities.dp(18), Utilities.dp(9), Utilities.dp(9), 0); + } else if (messageType == 18) { + holder.chatBubbleView.setBackgroundResource(R.drawable.chat_outgoing_text_states); + holder.chatBubbleView.setPadding(Utilities.dp(9), Utilities.dp(9), Utilities.dp(18), Utilities.dp(6)); + } + } else { + if (messageType == 2 || messageType == 4 || messageType == 6) { + if (selected) { + holder.chatBubbleView.setBackgroundResource(R.drawable.msg_out_photo_selected); } else { - if (messageType == 2 || messageType == 4 || messageType == 6) { - if (selected) { - holder.chatBubbleView.setBackgroundResource(R.drawable.msg_out_photo_selected); - } else { - holder.chatBubbleView.setBackgroundResource(R.drawable.msg_out_photo); - } - } else if (messageType == 3 || messageType == 5 || messageType == 7) { - if (selected) { - holder.chatBubbleView.setBackgroundResource(R.drawable.msg_in_photo_selected); - } else { - holder.chatBubbleView.setBackgroundResource(R.drawable.msg_in_photo); - } - } else if (messageType == 0 || messageType == 8) { - if (selected) { - holder.messageLayout.setBackgroundResource(R.drawable.msg_out_selected); - } else { - holder.messageLayout.setBackgroundResource(R.drawable.msg_out); - } - holder.messageLayout.setPadding(Utilities.dp(11), Utilities.dp(7), Utilities.dp(18), 0); - } else if (messageType == 1 || messageType == 9) { - if (selected) { - holder.messageLayout.setBackgroundResource(R.drawable.msg_in_selected); - } else { - holder.messageLayout.setBackgroundResource(R.drawable.msg_in); - } - holder.messageLayout.setPadding(Utilities.dp(19), Utilities.dp(7), Utilities.dp(9), 0); - } else if (messageType == 12) { - if (selected) { - holder.chatBubbleView.setBackgroundResource(R.drawable.msg_out_selected); - } else { - holder.chatBubbleView.setBackgroundResource(R.drawable.msg_out); - } - holder.chatBubbleView.setPadding(Utilities.dp(6), Utilities.dp(6), Utilities.dp(18), 0); - } else if (messageType == 13) { - if (selected) { - holder.chatBubbleView.setBackgroundResource(R.drawable.msg_in_selected); - } else { - holder.chatBubbleView.setBackgroundResource(R.drawable.msg_in); - } - holder.chatBubbleView.setPadding(Utilities.dp(15), Utilities.dp(6), Utilities.dp(9), 0); - } else if (messageType == 16) { - if (selected) { - holder.chatBubbleView.setBackgroundResource(R.drawable.msg_out_selected); - } else { - holder.chatBubbleView.setBackgroundResource(R.drawable.msg_out); - } - holder.chatBubbleView.setPadding(Utilities.dp(9), Utilities.dp(9), Utilities.dp(18), 0); - } else if (messageType == 17) { - if (selected) { - holder.chatBubbleView.setBackgroundResource(R.drawable.msg_in_selected); - } else { - holder.chatBubbleView.setBackgroundResource(R.drawable.msg_in); - } - holder.chatBubbleView.setPadding(Utilities.dp(18), Utilities.dp(9), Utilities.dp(9), 0); - } + holder.chatBubbleView.setBackgroundResource(R.drawable.msg_out_photo); } + } else if (messageType == 3 || messageType == 5 || messageType == 7) { + if (selected) { + holder.chatBubbleView.setBackgroundResource(R.drawable.msg_in_photo_selected); + } else { + holder.chatBubbleView.setBackgroundResource(R.drawable.msg_in_photo); + } + } else if (messageType == 0 || messageType == 8) { + if (selected) { + holder.messageLayout.setBackgroundResource(R.drawable.msg_out_selected); + } else { + holder.messageLayout.setBackgroundResource(R.drawable.msg_out); + } + holder.messageLayout.setPadding(Utilities.dp(11), Utilities.dp(7), Utilities.dp(18), 0); + } else if (messageType == 1 || messageType == 9) { + if (selected) { + holder.messageLayout.setBackgroundResource(R.drawable.msg_in_selected); + } else { + holder.messageLayout.setBackgroundResource(R.drawable.msg_in); + } + holder.messageLayout.setPadding(Utilities.dp(19), Utilities.dp(7), Utilities.dp(9), 0); + } else if (messageType == 12) { + if (selected) { + holder.chatBubbleView.setBackgroundResource(R.drawable.msg_out_selected); + } else { + holder.chatBubbleView.setBackgroundResource(R.drawable.msg_out); + } + holder.chatBubbleView.setPadding(Utilities.dp(6), Utilities.dp(6), Utilities.dp(18), 0); + } else if (messageType == 13) { + if (selected) { + holder.chatBubbleView.setBackgroundResource(R.drawable.msg_in_selected); + } else { + holder.chatBubbleView.setBackgroundResource(R.drawable.msg_in); + } + holder.chatBubbleView.setPadding(Utilities.dp(15), Utilities.dp(6), Utilities.dp(9), 0); + } else if (messageType == 16) { + if (selected) { + holder.chatBubbleView.setBackgroundResource(R.drawable.msg_out_selected); + } else { + holder.chatBubbleView.setBackgroundResource(R.drawable.msg_out); + } + holder.chatBubbleView.setPadding(Utilities.dp(9), Utilities.dp(9), Utilities.dp(18), 0); + } else if (messageType == 17) { + if (selected) { + holder.chatBubbleView.setBackgroundResource(R.drawable.msg_in_selected); + } else { + holder.chatBubbleView.setBackgroundResource(R.drawable.msg_in); + } + holder.chatBubbleView.setPadding(Utilities.dp(18), Utilities.dp(9), Utilities.dp(9), 0); + } else if (messageType == 18) { + if (selected) { + holder.chatBubbleView.setBackgroundResource(R.drawable.msg_out_selected); + } else { + holder.chatBubbleView.setBackgroundResource(R.drawable.msg_out); + } + holder.chatBubbleView.setPadding(Utilities.dp(9), Utilities.dp(9), Utilities.dp(18), Utilities.dp(6)); } } } @@ -2952,6 +3071,14 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa } else { view = li.inflate(R.layout.chat_incoming_document_layout, viewGroup, false); } + } else if (type == 18) { + view = li.inflate(R.layout.chat_outgoing_audio_layout, viewGroup, false); + } else if (type == 19) { + if (currentChat != null) { + view = li.inflate(R.layout.chat_group_incoming_document_layout, viewGroup, false); + } else { + view = li.inflate(R.layout.chat_incoming_document_layout, viewGroup, false); + } } } @@ -2975,89 +3102,7 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa } else { view.setBackgroundColor(0); } - int messageType = holder.message.type; - if (!disableSelection) { - if (messageType == 2 || messageType == 4 || messageType == 6) { - holder.chatBubbleView.setBackgroundResource(R.drawable.chat_outgoing_photo_states); - } else if (messageType == 3 || messageType == 5 || messageType == 7) { - holder.chatBubbleView.setBackgroundResource(R.drawable.chat_incoming_photo_states); - } else if (messageType == 0 || messageType == 8) { - holder.messageLayout.setBackgroundResource(R.drawable.chat_outgoing_text_states); - holder.messageLayout.setPadding(Utilities.dp(11), Utilities.dp(7), Utilities.dp(18), 0); - } else if (messageType == 1 || messageType == 9) { - holder.messageLayout.setBackgroundResource(R.drawable.chat_incoming_text_states); - holder.messageLayout.setPadding(Utilities.dp(19), Utilities.dp(7), Utilities.dp(9), 0); - } else if (messageType == 12) { - holder.chatBubbleView.setBackgroundResource(R.drawable.chat_outgoing_text_states); - holder.chatBubbleView.setPadding(Utilities.dp(6), Utilities.dp(6), Utilities.dp(18), 0); - } else if (messageType == 13) { - holder.chatBubbleView.setBackgroundResource(R.drawable.chat_incoming_text_states); - holder.chatBubbleView.setPadding(Utilities.dp(15), Utilities.dp(6), Utilities.dp(9), 0); - } else if (messageType == 16) { - holder.chatBubbleView.setBackgroundResource(R.drawable.chat_outgoing_text_states); - holder.chatBubbleView.setPadding(Utilities.dp(9), Utilities.dp(9), Utilities.dp(18), 0); - } else if (messageType == 17) { - holder.chatBubbleView.setBackgroundResource(R.drawable.chat_incoming_text_states); - holder.chatBubbleView.setPadding(Utilities.dp(18), Utilities.dp(9), Utilities.dp(9), 0); - } - } else { - if (messageType == 2 || messageType == 4 || messageType == 6) { - if (selected) { - holder.chatBubbleView.setBackgroundResource(R.drawable.msg_out_photo_selected); - } else { - holder.chatBubbleView.setBackgroundResource(R.drawable.msg_out_photo); - } - } else if (messageType == 3 || messageType == 5 || messageType == 7) { - if (selected) { - holder.chatBubbleView.setBackgroundResource(R.drawable.msg_in_photo_selected); - } else { - holder.chatBubbleView.setBackgroundResource(R.drawable.msg_in_photo); - } - } else if (messageType == 0 || messageType == 8) { - if (selected) { - holder.messageLayout.setBackgroundResource(R.drawable.msg_out_selected); - } else { - holder.messageLayout.setBackgroundResource(R.drawable.msg_out); - } - holder.messageLayout.setPadding(Utilities.dp(11), Utilities.dp(7), Utilities.dp(18), 0); - } else if (messageType == 1 || messageType == 9) { - if (selected) { - holder.messageLayout.setBackgroundResource(R.drawable.msg_in_selected); - } else { - holder.messageLayout.setBackgroundResource(R.drawable.msg_in); - } - holder.messageLayout.setPadding(Utilities.dp(19), Utilities.dp(7), Utilities.dp(9), 0); - } else if (messageType == 12) { - if (selected) { - holder.chatBubbleView.setBackgroundResource(R.drawable.msg_out_selected); - } else { - holder.chatBubbleView.setBackgroundResource(R.drawable.msg_out); - } - holder.chatBubbleView.setPadding(Utilities.dp(6), Utilities.dp(6), Utilities.dp(18), 0); - } else if (messageType == 13) { - if (selected) { - holder.chatBubbleView.setBackgroundResource(R.drawable.msg_in_selected); - } else { - holder.chatBubbleView.setBackgroundResource(R.drawable.msg_in); - } - holder.chatBubbleView.setPadding(Utilities.dp(15), Utilities.dp(6), Utilities.dp(9), 0); - } else if (messageType == 16) { - if (selected) { - holder.chatBubbleView.setBackgroundResource(R.drawable.msg_out_selected); - } else { - holder.chatBubbleView.setBackgroundResource(R.drawable.msg_out); - } - holder.chatBubbleView.setPadding(Utilities.dp(9), Utilities.dp(9), Utilities.dp(18), 0); - } else if (messageType == 17) { - if (selected) { - holder.chatBubbleView.setBackgroundResource(R.drawable.msg_in_selected); - } else { - holder.chatBubbleView.setBackgroundResource(R.drawable.msg_in); - } - holder.chatBubbleView.setPadding(Utilities.dp(18), Utilities.dp(9), Utilities.dp(9), 0); - } - } - + updateRowBackground(holder, disableSelection, selected); holder.update(); return view; @@ -3081,7 +3126,7 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa @Override public int getViewTypeCount() { - return 18; + return 20; } @Override @@ -3673,7 +3718,7 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa processRowSelect(view); return; } - if (message.messageOwner.media.user_id != UserConfig.clientUserId) { + if (message.messageOwner.media.user_id != UserConfig.clientUserId && message.messageOwner.media.user_id != 0) { UserProfileActivity fragment = new UserProfileActivity(); Bundle args = new Bundle(); args.putInt("user_id", message.messageOwner.media.user_id); @@ -3738,9 +3783,9 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa if (file != null) { loadingFile.remove(file); if (message.type == 6 || message.type == 7) { - FileLoader.Instance.cancelLoadFile(message.messageOwner.media.video, null, null); + FileLoader.Instance.cancelLoadFile(message.messageOwner.media.video, null, null, null); } else if (message.type == 16 || message.type == 17) { - FileLoader.Instance.cancelLoadFile(null, null, message.messageOwner.media.document); + FileLoader.Instance.cancelLoadFile(null, null, message.messageOwner.media.document, null); } updateVisibleRows(); } @@ -3899,9 +3944,9 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa progressByTag.put((Integer)actionProgress.getTag(), fileName); addToLoadingFile(fileName, actionProgress); if (message.type == 6 || message.type == 7) { - FileLoader.Instance.loadFile(message.messageOwner.media.video, null, null); + FileLoader.Instance.loadFile(message.messageOwner.media.video, null, null, null); } else if (message.type == 16 || message.type == 17) { - FileLoader.Instance.loadFile(null, null, message.messageOwner.media.document); + FileLoader.Instance.loadFile(null, null, message.messageOwner.media.document, null); } updateVisibleRows(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ContactsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ContactsActivity.java index 7d9742281..765cca3c7 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ContactsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ContactsActivity.java @@ -8,10 +8,12 @@ package org.telegram.ui; +import android.app.Activity; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; +import android.content.SharedPreferences; import android.net.Uri; import android.os.Bundle; import android.support.v4.internal.view.SupportMenuItem; @@ -30,12 +32,15 @@ import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.TextView; +import org.telegram.TL.TLObject; import org.telegram.TL.TLRPC; +import org.telegram.messenger.ConnectionsManager; import org.telegram.messenger.ContactsController; import org.telegram.messenger.FileLog; import org.telegram.messenger.MessagesController; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; +import org.telegram.messenger.RPCRequest; import org.telegram.messenger.UserConfig; import org.telegram.messenger.Utilities; import org.telegram.ui.Cells.ChatOrUserCell; @@ -48,6 +53,7 @@ import java.lang.reflect.Field; import java.util.ArrayList; import java.util.HashMap; +import java.util.Locale; import java.util.Timer; import java.util.TimerTask; @@ -70,6 +76,8 @@ public class ContactsActivity extends BaseFragment implements NotificationCenter private SupportMenuItem searchItem; private Timer searchDialogsTimer; + private String inviteText; + private boolean updatingInviteText = false; public ArrayList searchResult; public ArrayList searchResultNames; public ContactsActivityDelegate delegate; @@ -95,6 +103,15 @@ public class ContactsActivity extends BaseFragment implements NotificationCenter ignoreUsers = (HashMap)NotificationCenter.Instance.getFromMemCache(7); } } + + + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); + inviteText = preferences.getString("invitetext", null); + int time = preferences.getInt("invitetexttime", 0); + if (inviteText == null || time + 86400 < (int)(System.currentTimeMillis() / 1000)) { + updateInviteText(); + } + return true; } @@ -165,14 +182,20 @@ public class ContactsActivity extends BaseFragment implements NotificationCenter } else { int section = listViewAdapter.getSectionForPosition(i); int row = listViewAdapter.getPositionInSectionForPosition(i); + if (row < 0 || section < 0) { + return; + } TLRPC.User user = null; if (usersAsSections) { if (section < ContactsController.Instance.sortedUsersSectionsArray.size()) { ArrayList arr = ContactsController.Instance.usersSectionsDict.get(ContactsController.Instance.sortedUsersSectionsArray.get(section)); - if (row >= arr.size()) { + if (row < arr.size()) { + TLRPC.TL_contact contact = arr.get(row); + user = MessagesController.Instance.users.get(contact.user_id); + } else { return; } - user = MessagesController.Instance.users.get(arr.get(row).user_id); + } } else { if (section == 0) { @@ -180,7 +203,7 @@ public class ContactsActivity extends BaseFragment implements NotificationCenter try { Intent intent = new Intent(Intent.ACTION_SEND); intent.setType("text/plain"); - intent.putExtra(Intent.EXTRA_TEXT, getStringEntry(R.string.InviteText)); + intent.putExtra(Intent.EXTRA_TEXT, inviteText != null ? inviteText : getStringEntry(R.string.InviteText)); startActivity(intent); } catch (Exception e) { FileLog.e("tmessages", e); @@ -554,6 +577,41 @@ public class ContactsActivity extends BaseFragment implements NotificationCenter } } + private void updateInviteText() { + if (updatingInviteText) { + return; + } + updatingInviteText = true; + TLRPC.TL_help_getInviteText req = new TLRPC.TL_help_getInviteText(); + req.lang_code = Locale.getDefault().getCountry(); + if (req.lang_code == null || req.lang_code.length() == 0) { + req.lang_code = "en"; + } + ConnectionsManager.Instance.performRpc(req, new RPCRequest.RPCRequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + if (error != null) { + return; + } + final TLRPC.TL_help_inviteText res = (TLRPC.TL_help_inviteText)response; + if (res.message.length() == 0) { + return; + } + Utilities.RunOnUIThread(new Runnable() { + @Override + public void run() { + updatingInviteText = false; + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); + SharedPreferences.Editor editor = preferences.edit(); + editor.putString("invitetext", res.message); + editor.putInt("invitetexttime", (int) (System.currentTimeMillis() / 1000)); + editor.commit(); + } + }); + } + }, null, true, RPCRequest.RPCRequestClassGeneric | RPCRequest.RPCRequestClassFailOnServerErrors); + } + private void updateVisibleRows(int mask) { if (listView == null) { return; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/GalleryImageViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/GalleryImageViewer.java index 14e1f65b0..9c1f4a3a8 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/GalleryImageViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/GalleryImageViewer.java @@ -67,6 +67,7 @@ public class GalleryImageViewer extends AbstractGalleryActivity implements Notif private String currentFileName; private int user_id = 0; private Point displaySize = new Point(); + private boolean cancelRunning = false; private ArrayList imagesArrTemp = new ArrayList(); private HashMap imagesByIdsTemp = new HashMap(); @@ -224,7 +225,7 @@ public class GalleryImageViewer extends AbstractGalleryActivity implements Notif deleteButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { - if (mViewPager == null) { + if (mViewPager == null || localPagerAdapter == null || localPagerAdapter.imagesArr == null) { return; } int item = mViewPager.getCurrentItem(); @@ -645,9 +646,20 @@ public class GalleryImageViewer extends AbstractGalleryActivity implements Notif } } + @Override + public void onBackPressed() { + super.onBackPressed(); + cancelRunning = true; + mViewPager.setAdapter(null); + localPagerAdapter = null; + finish(); + System.gc(); + } + private void processSelectedMenu(int itemId) { switch (itemId) { case android.R.id.home: + cancelRunning = true; mViewPager.setAdapter(null); localPagerAdapter = null; finish(); @@ -958,9 +970,9 @@ public class GalleryImageViewer extends AbstractGalleryActivity implements Notif } if (loadFile) { if (!FileLoader.Instance.isLoadingFile(fileName)) { - FileLoader.Instance.loadFile(message.messageOwner.media.video, null, null); + FileLoader.Instance.loadFile(message.messageOwner.media.video, null, null, null); } else { - FileLoader.Instance.cancelLoadFile(message.messageOwner.media.video, null, null); + FileLoader.Instance.cancelLoadFile(message.messageOwner.media.video, null, null, null); } checkCurrentFile(); processViews(playButton, message); @@ -988,7 +1000,9 @@ public class GalleryImageViewer extends AbstractGalleryActivity implements Notif public void destroyItem(View collection, int position, Object view) { ((ViewPager)collection).removeView((View)view); PZSImageView iv = (PZSImageView)((View)view).findViewById(R.id.page_image); - FileLoader.Instance.cancelLoadingForImageView(iv); + if (cancelRunning) { + FileLoader.Instance.cancelLoadingForImageView(iv); + } iv.clearImage(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java index c7acff8b4..65a32b3a3 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java @@ -54,7 +54,7 @@ public class LaunchActivity extends PausableActivity { } String path = null; if (parcelable instanceof Uri) { - path = Utilities.getPath(this, (Uri)parcelable); + path = Utilities.getPath((Uri)parcelable); } else { path = intent.getParcelableExtra(Intent.EXTRA_STREAM).toString(); if (path.startsWith("content:")) { @@ -79,7 +79,7 @@ public class LaunchActivity extends PausableActivity { } String path = null; if (parcelable instanceof Uri) { - path = Utilities.getPath(this, (Uri)parcelable); + path = Utilities.getPath((Uri)parcelable); } else { path = parcelable.toString(); if (path.startsWith("content:")) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LoginActivityPhoneView.java b/TMessagesProj/src/main/java/org/telegram/ui/LoginActivityPhoneView.java index 5bde3e5a7..c7b0cfa37 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LoginActivityPhoneView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LoginActivityPhoneView.java @@ -253,7 +253,9 @@ public class LoginActivityPhoneView extends SlideView implements AdapterView.OnI public void selectCountry(String name) { int index = countriesArray.indexOf(name); if (index != -1) { + ignoreOnTextChange = true; codeField.setText(countriesMap.get(name)); + countryButton.setText(name); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PhotoCropActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PhotoCropActivity.java new file mode 100644 index 000000000..073e425e2 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/PhotoCropActivity.java @@ -0,0 +1,381 @@ +/* + * This is the source code of Telegram for Android v. 1.3.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013. + */ + +package org.telegram.ui; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Point; +import android.graphics.drawable.BitmapDrawable; +import android.os.Bundle; +import android.support.v7.app.ActionBar; +import android.util.AttributeSet; +import android.view.Display; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.view.WindowManager; +import android.widget.FrameLayout; + +import org.telegram.messenger.FileLoader; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.R; +import org.telegram.messenger.Utilities; +import org.telegram.ui.Views.BaseFragment; + +import java.io.File; + +public class PhotoCropActivity extends BaseFragment { + + public interface PhotoCropActivityDelegate { + public abstract void didFinishCrop(Bitmap bitmap); + } + + private class PhotoCropView extends FrameLayout { + + Paint rectPaint = null; + Paint circlePaint = null; + Paint halfPaint = null; + float rectSize = 600; + float rectX = -1, rectY = -1; + int draggingState = 0; + float oldX = 0, oldY = 0; + int bitmapWidth, bitmapHeight, bitmapX, bitmapY; + int viewWidth, viewHeight; + + public PhotoCropView(Context context) { + super(context); + init(); + } + + public PhotoCropView(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + public PhotoCropView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + init(); + } + + private void init() { + rectPaint = new Paint(); + rectPaint.setColor(0xfffafafa); + rectPaint.setStrokeWidth(Utilities.dp(2)); + rectPaint.setStyle(Paint.Style.STROKE); + circlePaint = new Paint(); + circlePaint.setColor(0x7fffffff); + halfPaint = new Paint(); + halfPaint.setColor(0x3f000000); + setBackgroundColor(0xff000000); + + setOnTouchListener(new OnTouchListener() { + @Override + public boolean onTouch(View view, MotionEvent motionEvent) { + float x = motionEvent.getX(); + float y = motionEvent.getY(); + int cornerSide = Utilities.dp(14); + if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) { + if (rectX - cornerSide < x && rectX + cornerSide > x && rectY - cornerSide < y && rectY + cornerSide > y) { + draggingState = 1; + } else if (rectX - cornerSide + rectSize < x && rectX + cornerSide + rectSize > x && rectY - cornerSide < y && rectY + cornerSide > y) { + draggingState = 2; + } else if (rectX - cornerSide < x && rectX + cornerSide > x && rectY - cornerSide + rectSize < y && rectY + cornerSide + rectSize > y) { + draggingState = 3; + } else if (rectX - cornerSide + rectSize < x && rectX + cornerSide + rectSize > x && rectY - cornerSide + rectSize < y && rectY + cornerSide + rectSize > y) { + draggingState = 4; + } else if (rectX < x && rectX + rectSize > x && rectY < y && rectY + rectSize > y) { + draggingState = 5; + } else { + draggingState = 0; + } + oldX = x; + oldY = y; + } else if (motionEvent.getAction() == MotionEvent.ACTION_UP) { + draggingState = 0; + } else if (motionEvent.getAction() == MotionEvent.ACTION_MOVE && draggingState != 0) { + float diffX = x - oldX; + float diffY = y - oldY; + if (draggingState == 5) { + rectX += diffX; + rectY += diffY; + + if (rectX < bitmapX) { + rectX = bitmapX; + } else if (rectX + rectSize > bitmapX + bitmapWidth) { + rectX = bitmapX + bitmapWidth - rectSize; + } + if (rectY < bitmapY) { + rectY = bitmapY; + } else if (rectY + rectSize > bitmapY + bitmapHeight) { + rectY = bitmapY + bitmapHeight - rectSize; + } + } else if (draggingState == 1) { + if (rectSize - diffX < 160) { + diffX = rectSize - 160; + } + if (rectX + diffX < bitmapX) { + diffX = bitmapX - rectX; + } + if (rectY + diffX < bitmapY) { + diffX = bitmapY - rectY; + } + rectX += diffX; + rectY += diffX; + rectSize -= diffX; + } else if (draggingState == 2) { + if (rectSize + diffX < 160) { + diffX = -(rectSize - 160); + } + if (rectX + rectSize + diffX > bitmapX + bitmapWidth) { + diffX = bitmapX + bitmapWidth - rectX - rectSize; + } + if (rectY - diffX < bitmapY) { + diffX = rectY - bitmapY; + } + rectY -= diffX; + rectSize += diffX; + } else if (draggingState == 3) { + if (rectSize - diffX < 160) { + diffX = rectSize - 160; + } + if (rectX + diffX < bitmapX) { + diffX = bitmapX - rectX; + } + if (rectY + rectSize - diffX > bitmapY + bitmapHeight) { + diffX = rectY + rectSize - bitmapY - bitmapHeight; + } + rectX += diffX; + rectSize -= diffX; + } else if (draggingState == 4) { + if (rectX + rectSize + diffX > bitmapX + bitmapWidth) { + diffX = bitmapX + bitmapWidth - rectX - rectSize; + } + if (rectY + rectSize + diffX > bitmapY + bitmapHeight) { + diffX = bitmapY + bitmapHeight - rectY - rectSize; + } + rectSize += diffX; + if (rectSize < 160) { + rectSize = 160; + } + } + + oldX = x; + oldY = y; + invalidate(); + } + return true; + } + }); + } + + private void updateBitmapSize() { + if (viewWidth == 0 || viewHeight == 0) { + return; + } + float percX = (rectX - bitmapX) / bitmapWidth; + float percY = (rectY - bitmapY) / bitmapHeight; + float percSize = rectSize / bitmapWidth; + float w = imageToCrop.getWidth(); + float h = imageToCrop.getHeight(); + float scaleX = viewWidth / w; + float scaleY = viewHeight / h; + if (scaleX > scaleY) { + bitmapHeight = viewHeight; + bitmapWidth = (int)Math.ceil(w * scaleY); + } else { + bitmapWidth = viewWidth; + bitmapHeight = (int)Math.ceil(h * scaleX); + } + bitmapX = (viewWidth - bitmapWidth) / 2; + bitmapY = (viewHeight - bitmapHeight) / 2; + + if (rectX == -1 && rectY == -1) { + if (bitmapWidth > bitmapHeight) { + rectY = bitmapY; + rectX = (viewWidth - bitmapHeight) / 2; + rectSize = bitmapHeight; + } else { + rectX = bitmapX; + rectY = (viewHeight - bitmapWidth) / 2; + rectSize = bitmapWidth; + } + } else { + rectX = percX * bitmapWidth + bitmapX; + rectY = percY * bitmapHeight + bitmapY; + rectSize = percSize * bitmapWidth; + } + invalidate(); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + viewWidth = right - left; + viewHeight = bottom - top; + updateBitmapSize(); + } + + public Bitmap getBitmap() { + float percX = (rectX - bitmapX) / bitmapWidth; + float percY = (rectY - bitmapY) / bitmapHeight; + float percSize = rectSize / bitmapWidth; + int x = (int)(percX * imageToCrop.getWidth()); + int y = (int)(percY * imageToCrop.getHeight()); + int size = (int)(percSize * imageToCrop.getWidth()); + try { + return Bitmap.createBitmap(imageToCrop, x, y, size, size); + } catch (Exception e) { + FileLog.e("tmessags", e); + System.gc(); + try { + return Bitmap.createBitmap(imageToCrop, x, y, size, size); + } catch (Exception e2) { + FileLog.e("tmessages", e2); + } + } + return null; + } + + @Override + protected void onDraw(Canvas canvas) { + if (drawable != null) { + drawable.setBounds(bitmapX, bitmapY, bitmapX + bitmapWidth, bitmapY + bitmapHeight); + drawable.draw(canvas); + } + canvas.drawRect(bitmapX, bitmapY, bitmapX + bitmapWidth, rectY, halfPaint); + canvas.drawRect(bitmapX, rectY, rectX, rectY + rectSize, halfPaint); + canvas.drawRect(rectX + rectSize, rectY, bitmapX + bitmapWidth, rectY + rectSize, halfPaint); + canvas.drawRect(bitmapX, rectY + rectSize, bitmapX + bitmapWidth, bitmapY + bitmapHeight, halfPaint); + + canvas.drawRect(rectX, rectY, rectX + rectSize, rectY + rectSize, rectPaint); + + int side = Utilities.dp(7); + canvas.drawRect(rectX - side, rectY - side, rectX + side, rectY + side, circlePaint); + canvas.drawRect(rectX + rectSize - side, rectY - side, rectX + rectSize + side, rectY + side, circlePaint); + canvas.drawRect(rectX - side, rectY + rectSize - side, rectX + side, rectY + rectSize + side, circlePaint); + canvas.drawRect(rectX + rectSize - side, rectY + rectSize - side, rectX + rectSize + side, rectY + rectSize + side, circlePaint); + } + } + + private Bitmap imageToCrop; + private BitmapDrawable drawable; + public PhotoCropActivityDelegate delegate = null; + private PhotoCropView view; + private boolean sameBitmap = false; + private boolean doneButtonPressed = false; + + @Override + public boolean onFragmentCreate() { + super.onFragmentCreate(); + String photoPath = getArguments().getString("photoPath"); + if (photoPath == null) { + return false; + } + File f = new File(photoPath); + if (!f.exists()) { + return false; + } + Point displaySize = new Point(); + Display display = ((WindowManager)ApplicationLoader.applicationContext.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); + if(android.os.Build.VERSION.SDK_INT < 13) { + displaySize.set(display.getWidth(), display.getHeight()); + } else { + display.getSize(displaySize); + } + int size = Math.max(displaySize.x, displaySize.y); + imageToCrop = FileLoader.loadBitmap(photoPath, size, size); + if (imageToCrop == null) { + return false; + } + drawable = new BitmapDrawable(imageToCrop); + return true; + } + + @Override + public void onFragmentDestroy() { + super.onFragmentDestroy(); + drawable = null; + if (imageToCrop != null && !sameBitmap) { + imageToCrop.recycle(); + imageToCrop = null; + } + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + if (fragmentView == null) { + fragmentView = view = new PhotoCropView(this.getActivity()); + fragmentView.setLayoutParams(new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT)); + } else { + ViewGroup parent = (ViewGroup)fragmentView.getParent(); + if (parent != null) { + parent.removeView(fragmentView); + } + } + return fragmentView; + } + + @Override + public boolean canApplyUpdateStatus() { + return false; + } + + @Override + public void applySelfActionBar() { + if (parentActivity == null) { + return; + } + ActionBar actionBar = parentActivity.getSupportActionBar(); + actionBar.setDisplayShowCustomEnabled(true); + actionBar.setDisplayShowHomeEnabled(false); + actionBar.setDisplayShowTitleEnabled(false); + actionBar.setDisplayHomeAsUpEnabled(false); + + actionBar.setCustomView(R.layout.settings_do_action_layout); + View cancelButton = actionBar.getCustomView().findViewById(R.id.cancel_button); + cancelButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + finishFragment(); + } + }); + View doneButton = actionBar.getCustomView().findViewById(R.id.done_button); + doneButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (delegate != null && !doneButtonPressed) { + Bitmap bitmap = view.getBitmap(); + if (bitmap == imageToCrop) { + sameBitmap = true; + } + delegate.didFinishCrop(bitmap); + doneButtonPressed = true; + } + finishFragment(); + } + }); + } + + @Override + public void onResume() { + super.onResume(); + if (getActivity() == null) { + return; + } + ((ApplicationActivity)parentActivity).updateActionBar(); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/SettingsWallpapersActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/SettingsWallpapersActivity.java index f793dd5ef..be4678a69 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/SettingsWallpapersActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/SettingsWallpapersActivity.java @@ -246,11 +246,11 @@ public class SettingsWallpapersActivity extends BaseFragment implements Notifica progressBar.setVisibility(View.VISIBLE); loadingSize = size; selectedColor = 0; - FileLoader.Instance.loadFile(null, size, null); + FileLoader.Instance.loadFile(null, size, null, null); backgroundImage.setBackgroundColor(0); } else { if (loadingFile != null) { - FileLoader.Instance.cancelLoadFile(null, loadingSize, null); + FileLoader.Instance.cancelLoadFile(null, loadingSize, null, null); } loadingFileObject = null; loadingFile = null; @@ -263,7 +263,7 @@ public class SettingsWallpapersActivity extends BaseFragment implements Notifica } } else { if (loadingFile != null) { - FileLoader.Instance.cancelLoadFile(null, loadingSize, null); + FileLoader.Instance.cancelLoadFile(null, loadingSize, null, null); } if (selectedBackground == 1000001) { backgroundImage.setImageResource(R.drawable.background_hd); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/UserProfileActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/UserProfileActivity.java index 279b95569..f81cc5ab1 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/UserProfileActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/UserProfileActivity.java @@ -78,7 +78,7 @@ public class UserProfileActivity extends BaseFragment implements NotificationCen if (dialog_id != 0) { currentEncryptedChat = MessagesController.Instance.encryptedChats.get((int)(dialog_id >> 32)); } - return true; + return MessagesController.Instance.users.get(user_id) != null; } @Override @@ -471,15 +471,9 @@ public class UserProfileActivity extends BaseFragment implements NotificationCen builder.setPositiveButton(getStringEntry(R.string.OK), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { - TLRPC.TL_auth_resetAuthorizations req = new TLRPC.TL_auth_resetAuthorizations(); - ConnectionsManager.Instance.performRpc(req, new RPCRequest.RPCRequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - ArrayList arrayList = new ArrayList(); - arrayList.add(user); - ContactsController.Instance.deleteContact(arrayList); - } - }, null, true, RPCRequest.RPCRequestClassGeneric); + ArrayList arrayList = new ArrayList(); + arrayList.add(user); + ContactsController.Instance.deleteContact(arrayList); } }); builder.setNegativeButton(getStringEntry(R.string.Cancel), null); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Views/AvatarUpdater.java b/TMessagesProj/src/main/java/org/telegram/ui/Views/AvatarUpdater.java index 04b67a591..3f576e371 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Views/AvatarUpdater.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Views/AvatarUpdater.java @@ -10,11 +10,10 @@ package org.telegram.ui.Views; import android.app.Activity; import android.content.Intent; -import android.database.Cursor; import android.graphics.Bitmap; import android.net.Uri; +import android.os.Bundle; import android.provider.MediaStore; -import android.support.v4.app.Fragment; import org.telegram.TL.TLRPC; import org.telegram.messenger.FileLoader; @@ -22,17 +21,19 @@ import org.telegram.messenger.FileLog; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.UserConfig; import org.telegram.messenger.Utilities; +import org.telegram.ui.ApplicationActivity; +import org.telegram.ui.PhotoCropActivity; import java.io.File; -public class AvatarUpdater implements NotificationCenter.NotificationCenterDelegate { +public class AvatarUpdater implements NotificationCenter.NotificationCenterDelegate, PhotoCropActivity.PhotoCropActivityDelegate { public String currentPicturePath; private TLRPC.PhotoSize smallPhoto; private TLRPC.PhotoSize bigPhoto; public String uploadingAvatar = null; File picturePath = null; public Activity parentActivity = null; - public Fragment parentFragment = null; + public BaseFragment parentFragment = null; public AvatarUpdaterDelegate delegate; private boolean clearAfterUpdate = false; public boolean returnOnly = false; @@ -85,22 +86,38 @@ public class AvatarUpdater implements NotificationCenter.NotificationCenterDeleg private void startCrop(String path) { try { - Intent cropIntent = new Intent("com.android.camera.action.CROP"); - cropIntent.setDataAndType(Uri.fromFile(new File(path)), "image/*"); - cropIntent.putExtra("crop", "true"); - cropIntent.putExtra("aspectX", 1); - cropIntent.putExtra("aspectY", 1); - cropIntent.putExtra("outputX", 800); - cropIntent.putExtra("outputY", 800); - cropIntent.putExtra("scale", true); - cropIntent.putExtra("return-data", false); - picturePath = Utilities.generatePicturePath(); - cropIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(picturePath)); - cropIntent.putExtra("output", Uri.fromFile(picturePath)); if (parentFragment != null) { - parentFragment.startActivityForResult(cropIntent, 2); - } else if (parentActivity != null) { - parentActivity.startActivityForResult(cropIntent, 2); + ApplicationActivity activity = (ApplicationActivity)parentFragment.parentActivity; + if (activity == null) { + activity = (ApplicationActivity)parentFragment.getActivity(); + } + if (activity == null) { + return; + } + Bundle params = new Bundle(); + params.putString("photoPath", path); + PhotoCropActivity photoCropActivity = new PhotoCropActivity(); + photoCropActivity.delegate = this; + photoCropActivity.setArguments(params); + activity.presentFragment(photoCropActivity, "crop", false); + } else { + Intent cropIntent = new Intent("com.android.camera.action.CROP"); + cropIntent.setDataAndType(Uri.fromFile(new File(path)), "image/*"); + cropIntent.putExtra("crop", "true"); + cropIntent.putExtra("aspectX", 1); + cropIntent.putExtra("aspectY", 1); + cropIntent.putExtra("outputX", 800); + cropIntent.putExtra("outputY", 800); + cropIntent.putExtra("scale", true); + cropIntent.putExtra("return-data", false); + picturePath = Utilities.generatePicturePath(); + cropIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(picturePath)); + cropIntent.putExtra("output", Uri.fromFile(picturePath)); + if (parentFragment != null) { + parentFragment.startActivityForResult(cropIntent, 2); + } else if (parentActivity != null) { + parentActivity.startActivityForResult(cropIntent, 2); + } } } catch (Exception e) { FileLog.e("tmessages", e); @@ -120,26 +137,15 @@ public class AvatarUpdater implements NotificationCenter.NotificationCenterDeleg if (data == null) { return; } - Uri imageUri = data.getData(); - Cursor cursor = null; try { - if (parentFragment != null) { - cursor = parentFragment.getActivity().getContentResolver().query(imageUri, new String[]{android.provider.MediaStore.Images.ImageColumns.DATA}, null, null, null); - } else if (parentActivity != null) { - cursor = parentActivity.getContentResolver().query(imageUri, new String[]{android.provider.MediaStore.Images.ImageColumns.DATA}, null, null, null); + Uri imageUri = data.getData(); + if (imageUri != null) { + String imageFilePath = Utilities.getPath(imageUri); + startCrop(imageFilePath); } } catch (Exception e) { FileLog.e("tmessages", e); - return; } - if (cursor == null) { - return; - } - if (cursor.moveToFirst()) { - String imageFilePath = cursor.getString(0); - startCrop(imageFilePath); - } - cursor.close(); } else if (requestCode == 2) { Bitmap bitmap = FileLoader.loadBitmap(picturePath.getAbsolutePath(), 800, 800); processBitmap(bitmap); @@ -168,6 +174,11 @@ public class AvatarUpdater implements NotificationCenter.NotificationCenterDeleg } } + @Override + public void didFinishCrop(Bitmap bitmap) { + processBitmap(bitmap); + } + @Override public void didReceivedNotification(int id, final Object... args) { if (id == FileLoader.FileDidUpload) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Views/LayoutListView.java b/TMessagesProj/src/main/java/org/telegram/ui/Views/LayoutListView.java index 9c6636634..fa037f109 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Views/LayoutListView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Views/LayoutListView.java @@ -40,11 +40,19 @@ public class LayoutListView extends ListView { post(new Runnable() { @Override public void run() { - setSelectionFromTop(scrollTo, offset - getPaddingTop()); + try { + setSelectionFromTop(scrollTo, offset - getPaddingTop()); + } catch (Exception e) { + e.printStackTrace(); + } } }); } else { - super.onLayout(changed, left, top, right, bottom); + try { + super.onLayout(changed, left, top, right, bottom); + } catch (Exception e) { + e.printStackTrace(); + } } height = (bottom - top); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Views/SeekBar.java b/TMessagesProj/src/main/java/org/telegram/ui/Views/SeekBar.java new file mode 100644 index 000000000..0d55da6ac --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Views/SeekBar.java @@ -0,0 +1,135 @@ +/* + * This is the source code of Telegram for Android v. 1.3.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013. + */ + +package org.telegram.ui.Views; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.drawable.Drawable; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; + +import org.telegram.messenger.R; +import org.telegram.messenger.Utilities; + +public class SeekBar extends View { + Drawable thumbDrawable1; + Drawable thumbDrawablePressed1; + Drawable thumbDrawable2; + Drawable thumbDrawablePressed2; + static Paint innerPaint1 = new Paint(); + static Paint outerPaint1 = new Paint(); + static Paint innerPaint2 = new Paint(); + static Paint outerPaint2 = new Paint(); + public int type; + public int thumbX = 0; + public int thumbDX = 0; + private boolean pressed = false; + private boolean dragging = false; + private int thumbWidth; + private int thumbHeight; + + public SeekBar(Context context) { + super(context); + init(); + } + + public SeekBar(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + public SeekBar(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(); + } + + private void init() { + if (thumbDrawable1 == null) { + thumbDrawable1 = getResources().getDrawable(R.drawable.player1); + thumbDrawablePressed1 = getResources().getDrawable(R.drawable.player1_pressed); + thumbDrawable2 = getResources().getDrawable(R.drawable.player2); + thumbDrawablePressed2 = getResources().getDrawable(R.drawable.player2_pressed); + innerPaint1.setColor(0xffb4e396); + outerPaint1.setColor(0xff6ac453); + innerPaint2.setColor(0xffd9e2eb); + outerPaint2.setColor(0xff86c5f8); + thumbWidth = thumbDrawable1.getIntrinsicWidth(); + thumbHeight = thumbDrawable1.getIntrinsicHeight(); + } + + setOnTouchListener(new OnTouchListener() { + @Override + public boolean onTouch(View view, MotionEvent motionEvent) { + float x = motionEvent.getX(); + float y = motionEvent.getY(); + if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) { + int additionWidth = (getMeasuredHeight() - thumbWidth) / 2; + if (thumbX - additionWidth <= x && x <= thumbX + thumbWidth + additionWidth && y >= 0 && y <= getMeasuredHeight()) { + pressed = true; + thumbDX = (int)(x - thumbX); + invalidate(); + getParent().requestDisallowInterceptTouchEvent(true); + return true; + } + } else if (motionEvent.getAction() == MotionEvent.ACTION_UP || motionEvent.getAction() == MotionEvent.ACTION_CANCEL) { + if (pressed) { + pressed = false; + invalidate(); + return true; + } + } else if (motionEvent.getAction() == MotionEvent.ACTION_MOVE) { + if (pressed) { + thumbX = (int)(x - thumbDX); + if (thumbX < 0) { + thumbX = 0; + } else if (thumbX > getMeasuredWidth() - thumbWidth) { + thumbX = getMeasuredWidth() - thumbWidth; + } + invalidate(); + return true; + } + } + return false; + } + }); + } + + @Override + protected void onDraw(Canvas canvas) { + Drawable thumb = null; + Paint inner = null; + Paint outer = null; + if (type == 0) { + if (!pressed) { + thumb = thumbDrawable1; + } else { + thumb = thumbDrawablePressed1; + } + inner = innerPaint1; + outer = outerPaint1; + } else if (type == 1) { + if (!pressed) { + thumb = thumbDrawable2; + } else { + thumb = thumbDrawablePressed2; + } + inner = innerPaint2; + outer = outerPaint2; + } + int height = getMeasuredHeight(); + int width = getMeasuredWidth(); + int y = (height - thumbHeight) / 2; + canvas.drawRect(thumbWidth / 2, height / 2 - Utilities.dp(1), width - thumbWidth / 2, height / 2 + Utilities.dp(1), inner); + canvas.drawRect(thumbWidth / 2, height / 2 - Utilities.dp(1), thumbWidth / 2 + thumbX, height / 2 + Utilities.dp(1), outer); + thumb.setBounds(thumbX, y, thumbX + thumbWidth, y + thumbHeight); + thumb.draw(canvas); + } +} diff --git a/TMessagesProj/src/main/res/drawable-hdpi/ic_send.png b/TMessagesProj/src/main/res/drawable-hdpi/ic_send.png index da37f8033..50e63ae1e 100755 Binary files a/TMessagesProj/src/main/res/drawable-hdpi/ic_send.png and b/TMessagesProj/src/main/res/drawable-hdpi/ic_send.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/ic_send_disabled.png b/TMessagesProj/src/main/res/drawable-hdpi/ic_send_disabled.png index 93b2f1604..4473d1c6f 100755 Binary files a/TMessagesProj/src/main/res/drawable-hdpi/ic_send_disabled.png and b/TMessagesProj/src/main/res/drawable-hdpi/ic_send_disabled.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/mic.png b/TMessagesProj/src/main/res/drawable-hdpi/mic.png new file mode 100755 index 000000000..75e7bbf83 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/mic.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/mic_pressed.png b/TMessagesProj/src/main/res/drawable-hdpi/mic_pressed.png new file mode 100755 index 000000000..3cf43e04b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/mic_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/pause1.png b/TMessagesProj/src/main/res/drawable-hdpi/pause1.png new file mode 100755 index 000000000..30e945f31 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/pause1.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/pause1_pressed.png b/TMessagesProj/src/main/res/drawable-hdpi/pause1_pressed.png new file mode 100755 index 000000000..0053b7b03 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/pause1_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/pause2.png b/TMessagesProj/src/main/res/drawable-hdpi/pause2.png new file mode 100755 index 000000000..f96f878e9 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/pause2.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/pause2_pressed.png b/TMessagesProj/src/main/res/drawable-hdpi/pause2_pressed.png new file mode 100755 index 000000000..c3bca6315 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/pause2_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/play1.png b/TMessagesProj/src/main/res/drawable-hdpi/play1.png new file mode 100755 index 000000000..8bb953bcf Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/play1.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/play1_pressed.png b/TMessagesProj/src/main/res/drawable-hdpi/play1_pressed.png new file mode 100755 index 000000000..d5d220250 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/play1_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/play2.png b/TMessagesProj/src/main/res/drawable-hdpi/play2.png new file mode 100755 index 000000000..775a87a6a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/play2.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/play2_pressed.png b/TMessagesProj/src/main/res/drawable-hdpi/play2_pressed.png new file mode 100755 index 000000000..08e691986 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/play2_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/player1.png b/TMessagesProj/src/main/res/drawable-hdpi/player1.png new file mode 100755 index 000000000..6ec1a5d28 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/player1.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/player1_pressed.png b/TMessagesProj/src/main/res/drawable-hdpi/player1_pressed.png new file mode 100755 index 000000000..f5698eb11 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/player1_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/player2.png b/TMessagesProj/src/main/res/drawable-hdpi/player2.png new file mode 100755 index 000000000..cb9f570bb Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/player2.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/player2_pressed.png b/TMessagesProj/src/main/res/drawable-hdpi/player2_pressed.png new file mode 100755 index 000000000..879278c30 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/player2_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/rec.png b/TMessagesProj/src/main/res/drawable-hdpi/rec.png new file mode 100755 index 000000000..a3ed5835a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/rec.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/slidearrow.png b/TMessagesProj/src/main/res/drawable-hdpi/slidearrow.png new file mode 100755 index 000000000..b04164901 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/slidearrow.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/tooltip.png b/TMessagesProj/src/main/res/drawable-hdpi/tooltip.png new file mode 100755 index 000000000..58ce90239 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/tooltip.png differ diff --git a/TMessagesProj/src/main/res/drawable-ldpi/ic_send.png b/TMessagesProj/src/main/res/drawable-ldpi/ic_send.png index f094ca909..9e921724d 100755 Binary files a/TMessagesProj/src/main/res/drawable-ldpi/ic_send.png and b/TMessagesProj/src/main/res/drawable-ldpi/ic_send.png differ diff --git a/TMessagesProj/src/main/res/drawable-ldpi/ic_send_disabled.png b/TMessagesProj/src/main/res/drawable-ldpi/ic_send_disabled.png index c7bd4e0a1..8a2c19b5a 100755 Binary files a/TMessagesProj/src/main/res/drawable-ldpi/ic_send_disabled.png and b/TMessagesProj/src/main/res/drawable-ldpi/ic_send_disabled.png differ diff --git a/TMessagesProj/src/main/res/drawable-ldpi/mic.png b/TMessagesProj/src/main/res/drawable-ldpi/mic.png new file mode 100755 index 000000000..ae464202a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-ldpi/mic.png differ diff --git a/TMessagesProj/src/main/res/drawable-ldpi/mic_pressed.png b/TMessagesProj/src/main/res/drawable-ldpi/mic_pressed.png new file mode 100755 index 000000000..761d1603e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-ldpi/mic_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-ldpi/pause1.png b/TMessagesProj/src/main/res/drawable-ldpi/pause1.png new file mode 100755 index 000000000..2c7ff54b4 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-ldpi/pause1.png differ diff --git a/TMessagesProj/src/main/res/drawable-ldpi/pause1_pressed.png b/TMessagesProj/src/main/res/drawable-ldpi/pause1_pressed.png new file mode 100755 index 000000000..4ef1f6a72 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-ldpi/pause1_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-ldpi/pause2.png b/TMessagesProj/src/main/res/drawable-ldpi/pause2.png new file mode 100755 index 000000000..812828743 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-ldpi/pause2.png differ diff --git a/TMessagesProj/src/main/res/drawable-ldpi/pause2_pressed.png b/TMessagesProj/src/main/res/drawable-ldpi/pause2_pressed.png new file mode 100755 index 000000000..b6fbdfd5b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-ldpi/pause2_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-ldpi/play1.png b/TMessagesProj/src/main/res/drawable-ldpi/play1.png new file mode 100755 index 000000000..df10a3ee1 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-ldpi/play1.png differ diff --git a/TMessagesProj/src/main/res/drawable-ldpi/play1_pressed.png b/TMessagesProj/src/main/res/drawable-ldpi/play1_pressed.png new file mode 100755 index 000000000..60aef6fbe Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-ldpi/play1_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-ldpi/play2.png b/TMessagesProj/src/main/res/drawable-ldpi/play2.png new file mode 100755 index 000000000..6eca1a394 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-ldpi/play2.png differ diff --git a/TMessagesProj/src/main/res/drawable-ldpi/play2_pressed.png b/TMessagesProj/src/main/res/drawable-ldpi/play2_pressed.png new file mode 100755 index 000000000..b3bdee286 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-ldpi/play2_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-ldpi/player1.png b/TMessagesProj/src/main/res/drawable-ldpi/player1.png new file mode 100755 index 000000000..e49d95d94 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-ldpi/player1.png differ diff --git a/TMessagesProj/src/main/res/drawable-ldpi/player1_pressed.png b/TMessagesProj/src/main/res/drawable-ldpi/player1_pressed.png new file mode 100755 index 000000000..32e7dde9e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-ldpi/player1_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-ldpi/player2.png b/TMessagesProj/src/main/res/drawable-ldpi/player2.png new file mode 100755 index 000000000..46551ea5e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-ldpi/player2.png differ diff --git a/TMessagesProj/src/main/res/drawable-ldpi/player2_pressed.png b/TMessagesProj/src/main/res/drawable-ldpi/player2_pressed.png new file mode 100755 index 000000000..c16103c39 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-ldpi/player2_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-ldpi/rec.png b/TMessagesProj/src/main/res/drawable-ldpi/rec.png new file mode 100755 index 000000000..2d08c58f6 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-ldpi/rec.png differ diff --git a/TMessagesProj/src/main/res/drawable-ldpi/slidearrow.png b/TMessagesProj/src/main/res/drawable-ldpi/slidearrow.png new file mode 100755 index 000000000..12fae28d7 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-ldpi/slidearrow.png differ diff --git a/TMessagesProj/src/main/res/drawable-ldpi/tooltip.png b/TMessagesProj/src/main/res/drawable-ldpi/tooltip.png new file mode 100755 index 000000000..4385e07b4 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-ldpi/tooltip.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/ic_send.png b/TMessagesProj/src/main/res/drawable-mdpi/ic_send.png index b5e5935a5..9d5a7c907 100755 Binary files a/TMessagesProj/src/main/res/drawable-mdpi/ic_send.png and b/TMessagesProj/src/main/res/drawable-mdpi/ic_send.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/ic_send_disabled.png b/TMessagesProj/src/main/res/drawable-mdpi/ic_send_disabled.png index d76dca75f..c183f5f92 100755 Binary files a/TMessagesProj/src/main/res/drawable-mdpi/ic_send_disabled.png and b/TMessagesProj/src/main/res/drawable-mdpi/ic_send_disabled.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/mic.png b/TMessagesProj/src/main/res/drawable-mdpi/mic.png new file mode 100755 index 000000000..2b9dec258 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/mic.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/mic_pressed.png b/TMessagesProj/src/main/res/drawable-mdpi/mic_pressed.png new file mode 100755 index 000000000..e1b29c5bc Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/mic_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/pause1.png b/TMessagesProj/src/main/res/drawable-mdpi/pause1.png new file mode 100755 index 000000000..35570d84a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/pause1.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/pause1_pressed.png b/TMessagesProj/src/main/res/drawable-mdpi/pause1_pressed.png new file mode 100755 index 000000000..557cac120 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/pause1_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/pause2.png b/TMessagesProj/src/main/res/drawable-mdpi/pause2.png new file mode 100755 index 000000000..50f4366db Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/pause2.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/pause2_pressed.png b/TMessagesProj/src/main/res/drawable-mdpi/pause2_pressed.png new file mode 100755 index 000000000..50305fead Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/pause2_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/play1.png b/TMessagesProj/src/main/res/drawable-mdpi/play1.png new file mode 100755 index 000000000..25cee312d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/play1.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/play1_pressed.png b/TMessagesProj/src/main/res/drawable-mdpi/play1_pressed.png new file mode 100755 index 000000000..124eb2479 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/play1_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/play2.png b/TMessagesProj/src/main/res/drawable-mdpi/play2.png new file mode 100755 index 000000000..9d5a7c907 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/play2.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/play2_pressed.png b/TMessagesProj/src/main/res/drawable-mdpi/play2_pressed.png new file mode 100755 index 000000000..52ce63376 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/play2_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/player1.png b/TMessagesProj/src/main/res/drawable-mdpi/player1.png new file mode 100755 index 000000000..ff66a1aa5 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/player1.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/player1_pressed.png b/TMessagesProj/src/main/res/drawable-mdpi/player1_pressed.png new file mode 100755 index 000000000..4bc5b5735 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/player1_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/player2.png b/TMessagesProj/src/main/res/drawable-mdpi/player2.png new file mode 100755 index 000000000..9d3caac8d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/player2.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/player2_pressed.png b/TMessagesProj/src/main/res/drawable-mdpi/player2_pressed.png new file mode 100755 index 000000000..946cf59d7 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/player2_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/rec.png b/TMessagesProj/src/main/res/drawable-mdpi/rec.png new file mode 100755 index 000000000..106e9f4a7 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/rec.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/slidearrow.png b/TMessagesProj/src/main/res/drawable-mdpi/slidearrow.png new file mode 100755 index 000000000..9206c2552 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/slidearrow.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/tooltip.png b/TMessagesProj/src/main/res/drawable-mdpi/tooltip.png new file mode 100755 index 000000000..01b2766d2 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/tooltip.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/ic_send.png b/TMessagesProj/src/main/res/drawable-xhdpi/ic_send.png index 73e990f38..4c42bc008 100755 Binary files a/TMessagesProj/src/main/res/drawable-xhdpi/ic_send.png and b/TMessagesProj/src/main/res/drawable-xhdpi/ic_send.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/ic_send_disabled.png b/TMessagesProj/src/main/res/drawable-xhdpi/ic_send_disabled.png index f4f0c36c4..d63101df2 100755 Binary files a/TMessagesProj/src/main/res/drawable-xhdpi/ic_send_disabled.png and b/TMessagesProj/src/main/res/drawable-xhdpi/ic_send_disabled.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/mic.png b/TMessagesProj/src/main/res/drawable-xhdpi/mic.png new file mode 100755 index 000000000..f8b453804 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/mic.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/mic_pressed.png b/TMessagesProj/src/main/res/drawable-xhdpi/mic_pressed.png new file mode 100755 index 000000000..62e655bea Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/mic_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/pause1.png b/TMessagesProj/src/main/res/drawable-xhdpi/pause1.png new file mode 100755 index 000000000..5a0abe48a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/pause1.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/pause1_pressed.png b/TMessagesProj/src/main/res/drawable-xhdpi/pause1_pressed.png new file mode 100755 index 000000000..799a2314b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/pause1_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/pause2.png b/TMessagesProj/src/main/res/drawable-xhdpi/pause2.png new file mode 100755 index 000000000..973b1675b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/pause2.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/pause2_pressed.png b/TMessagesProj/src/main/res/drawable-xhdpi/pause2_pressed.png new file mode 100755 index 000000000..09e75bb8c Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/pause2_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/play1.png b/TMessagesProj/src/main/res/drawable-xhdpi/play1.png new file mode 100755 index 000000000..442474dac Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/play1.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/play1_pressed.png b/TMessagesProj/src/main/res/drawable-xhdpi/play1_pressed.png new file mode 100755 index 000000000..9391b98f7 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/play1_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/play2.png b/TMessagesProj/src/main/res/drawable-xhdpi/play2.png new file mode 100755 index 000000000..a2bf525bd Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/play2.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/play2_pressed.png b/TMessagesProj/src/main/res/drawable-xhdpi/play2_pressed.png new file mode 100755 index 000000000..164ff9e10 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/play2_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/player1.png b/TMessagesProj/src/main/res/drawable-xhdpi/player1.png new file mode 100755 index 000000000..2a11310e6 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/player1.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/player1_pressed.png b/TMessagesProj/src/main/res/drawable-xhdpi/player1_pressed.png new file mode 100755 index 000000000..e3ebd1b5e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/player1_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/player2.png b/TMessagesProj/src/main/res/drawable-xhdpi/player2.png new file mode 100755 index 000000000..57bc079af Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/player2.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/player2_pressed.png b/TMessagesProj/src/main/res/drawable-xhdpi/player2_pressed.png new file mode 100755 index 000000000..03723d55b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/player2_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/rec.png b/TMessagesProj/src/main/res/drawable-xhdpi/rec.png new file mode 100755 index 000000000..9c03e36c4 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/rec.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/slidearrow.png b/TMessagesProj/src/main/res/drawable-xhdpi/slidearrow.png new file mode 100755 index 000000000..519e2b173 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/slidearrow.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/tooltip.png b/TMessagesProj/src/main/res/drawable-xhdpi/tooltip.png new file mode 100755 index 000000000..4e2da555c Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/tooltip.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/ic_send.png b/TMessagesProj/src/main/res/drawable-xxhdpi/ic_send.png index d55fade39..eec17c547 100755 Binary files a/TMessagesProj/src/main/res/drawable-xxhdpi/ic_send.png and b/TMessagesProj/src/main/res/drawable-xxhdpi/ic_send.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/ic_send_disabled.png b/TMessagesProj/src/main/res/drawable-xxhdpi/ic_send_disabled.png index 3108f5bb3..633bad32f 100755 Binary files a/TMessagesProj/src/main/res/drawable-xxhdpi/ic_send_disabled.png and b/TMessagesProj/src/main/res/drawable-xxhdpi/ic_send_disabled.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/mic.png b/TMessagesProj/src/main/res/drawable-xxhdpi/mic.png new file mode 100755 index 000000000..ba25d2612 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/mic.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/mic_pressed.png b/TMessagesProj/src/main/res/drawable-xxhdpi/mic_pressed.png new file mode 100755 index 000000000..c972af2bd Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/mic_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/pause1.png b/TMessagesProj/src/main/res/drawable-xxhdpi/pause1.png new file mode 100755 index 000000000..9293c448b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/pause1.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/pause1_pressed.png b/TMessagesProj/src/main/res/drawable-xxhdpi/pause1_pressed.png new file mode 100755 index 000000000..e86f91f93 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/pause1_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/pause2.png b/TMessagesProj/src/main/res/drawable-xxhdpi/pause2.png new file mode 100755 index 000000000..d18cf420d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/pause2.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/pause2_pressed.png b/TMessagesProj/src/main/res/drawable-xxhdpi/pause2_pressed.png new file mode 100755 index 000000000..f7259a314 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/pause2_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/play1.png b/TMessagesProj/src/main/res/drawable-xxhdpi/play1.png new file mode 100755 index 000000000..1c0924fdf Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/play1.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/play1_pressed.png b/TMessagesProj/src/main/res/drawable-xxhdpi/play1_pressed.png new file mode 100755 index 000000000..51642f673 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/play1_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/play2.png b/TMessagesProj/src/main/res/drawable-xxhdpi/play2.png new file mode 100755 index 000000000..d34c30371 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/play2.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/play2_pressed.png b/TMessagesProj/src/main/res/drawable-xxhdpi/play2_pressed.png new file mode 100755 index 000000000..cff0cf086 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/play2_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/player1.png b/TMessagesProj/src/main/res/drawable-xxhdpi/player1.png new file mode 100755 index 000000000..6eee90a8e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/player1.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/player1_pressed.png b/TMessagesProj/src/main/res/drawable-xxhdpi/player1_pressed.png new file mode 100755 index 000000000..f1af60fcc Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/player1_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/player2.png b/TMessagesProj/src/main/res/drawable-xxhdpi/player2.png new file mode 100755 index 000000000..7a099f7cb Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/player2.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/player2_pressed.png b/TMessagesProj/src/main/res/drawable-xxhdpi/player2_pressed.png new file mode 100755 index 000000000..8fb075f6f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/player2_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/rec.png b/TMessagesProj/src/main/res/drawable-xxhdpi/rec.png new file mode 100755 index 000000000..e95a6252b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/rec.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/slidearrow.png b/TMessagesProj/src/main/res/drawable-xxhdpi/slidearrow.png new file mode 100755 index 000000000..f60d77275 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/slidearrow.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/tooltip.png b/TMessagesProj/src/main/res/drawable-xxhdpi/tooltip.png new file mode 100755 index 000000000..e02e62b58 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/tooltip.png differ diff --git a/TMessagesProj/src/main/res/drawable/mic_button_states.xml b/TMessagesProj/src/main/res/drawable/mic_button_states.xml new file mode 100644 index 000000000..791017eda --- /dev/null +++ b/TMessagesProj/src/main/res/drawable/mic_button_states.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/TMessagesProj/src/main/res/drawable/pause1_states.xml b/TMessagesProj/src/main/res/drawable/pause1_states.xml new file mode 100644 index 000000000..79b4a63da --- /dev/null +++ b/TMessagesProj/src/main/res/drawable/pause1_states.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/TMessagesProj/src/main/res/drawable/pause2_states.xml b/TMessagesProj/src/main/res/drawable/pause2_states.xml new file mode 100644 index 000000000..741d3cb33 --- /dev/null +++ b/TMessagesProj/src/main/res/drawable/pause2_states.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/TMessagesProj/src/main/res/drawable/photo_progress_chat.xml b/TMessagesProj/src/main/res/drawable/photo_progress_chat.xml index e0d1896b5..37f07f523 100644 --- a/TMessagesProj/src/main/res/drawable/photo_progress_chat.xml +++ b/TMessagesProj/src/main/res/drawable/photo_progress_chat.xml @@ -1,11 +1,3 @@ - - @@ -15,7 +7,7 @@ - + diff --git a/TMessagesProj/src/main/res/drawable/play1_states.xml b/TMessagesProj/src/main/res/drawable/play1_states.xml new file mode 100644 index 000000000..cdb37c5f3 --- /dev/null +++ b/TMessagesProj/src/main/res/drawable/play1_states.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/TMessagesProj/src/main/res/drawable/play2_states.xml b/TMessagesProj/src/main/res/drawable/play2_states.xml new file mode 100644 index 000000000..c53194ad6 --- /dev/null +++ b/TMessagesProj/src/main/res/drawable/play2_states.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/TMessagesProj/src/main/res/drawable/progress_chat.xml b/TMessagesProj/src/main/res/drawable/progress_chat.xml new file mode 100644 index 000000000..0656b5e83 --- /dev/null +++ b/TMessagesProj/src/main/res/drawable/progress_chat.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/TMessagesProj/src/main/res/drawable/send_button_states.xml b/TMessagesProj/src/main/res/drawable/send_button_states.xml index 92132f986..90174a3d0 100644 --- a/TMessagesProj/src/main/res/drawable/send_button_states.xml +++ b/TMessagesProj/src/main/res/drawable/send_button_states.xml @@ -1,6 +1,6 @@ + - + \ No newline at end of file diff --git a/TMessagesProj/src/main/res/layout/chat_group_incoming_document_layout.xml b/TMessagesProj/src/main/res/layout/chat_group_incoming_document_layout.xml index 92c29c4db..c186aa4c6 100644 --- a/TMessagesProj/src/main/res/layout/chat_group_incoming_document_layout.xml +++ b/TMessagesProj/src/main/res/layout/chat_group_incoming_document_layout.xml @@ -106,7 +106,7 @@ android:layout_width="fill_parent" android:layout_height="3dp" android:layout_gravity="left|center_vertical" - android:progressDrawable="@drawable/photo_progress_chat" + android:progressDrawable="@drawable/progress_chat" style="?android:attr/progressBarStyleHorizontal" android:progress="50" android:layout_marginLeft="12dp" diff --git a/TMessagesProj/src/main/res/layout/chat_group_incoming_video_layout.xml b/TMessagesProj/src/main/res/layout/chat_group_incoming_video_layout.xml index 417f0d089..8af12c8d0 100644 --- a/TMessagesProj/src/main/res/layout/chat_group_incoming_video_layout.xml +++ b/TMessagesProj/src/main/res/layout/chat_group_incoming_video_layout.xml @@ -130,7 +130,7 @@ android:layout_width="fill_parent" android:layout_height="3dp" android:layout_gravity="left|center_vertical" - android:progressDrawable="@drawable/photo_progress_chat" + android:progressDrawable="@drawable/progress_chat" style="?android:attr/progressBarStyleHorizontal" android:progress="50" android:layout_marginLeft="12dp" diff --git a/TMessagesProj/src/main/res/layout/chat_incoming_document_layout.xml b/TMessagesProj/src/main/res/layout/chat_incoming_document_layout.xml index 5fa9cefa6..6911ef16a 100644 --- a/TMessagesProj/src/main/res/layout/chat_incoming_document_layout.xml +++ b/TMessagesProj/src/main/res/layout/chat_incoming_document_layout.xml @@ -96,7 +96,7 @@ android:layout_width="fill_parent" android:layout_height="3dp" android:layout_gravity="left|center_vertical" - android:progressDrawable="@drawable/photo_progress_chat" + android:progressDrawable="@drawable/progress_chat" style="?android:attr/progressBarStyleHorizontal" android:progress="50" android:layout_marginLeft="12dp" diff --git a/TMessagesProj/src/main/res/layout/chat_incoming_video_layout.xml b/TMessagesProj/src/main/res/layout/chat_incoming_video_layout.xml index 4f8802627..24a0d6a11 100644 --- a/TMessagesProj/src/main/res/layout/chat_incoming_video_layout.xml +++ b/TMessagesProj/src/main/res/layout/chat_incoming_video_layout.xml @@ -121,7 +121,7 @@ android:layout_width="fill_parent" android:layout_height="3dp" android:layout_gravity="left|center_vertical" - android:progressDrawable="@drawable/photo_progress_chat" + android:progressDrawable="@drawable/progress_chat" style="?android:attr/progressBarStyleHorizontal" android:progress="50" android:layout_marginLeft="12dp" diff --git a/TMessagesProj/src/main/res/layout/chat_layout.xml b/TMessagesProj/src/main/res/layout/chat_layout.xml index 3098d1a7d..6f7cc65f6 100644 --- a/TMessagesProj/src/main/res/layout/chat_layout.xml +++ b/TMessagesProj/src/main/res/layout/chat_layout.xml @@ -132,7 +132,7 @@ android:layout_alignBottom="@+id/chat_text_edit"/> + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/TMessagesProj/src/main/res/layout/chat_outgoing_document_layout.xml b/TMessagesProj/src/main/res/layout/chat_outgoing_document_layout.xml index 1845e7a8f..f948b65a5 100644 --- a/TMessagesProj/src/main/res/layout/chat_outgoing_document_layout.xml +++ b/TMessagesProj/src/main/res/layout/chat_outgoing_document_layout.xml @@ -37,7 +37,7 @@ android:layout_marginLeft="36dp" android:layout_marginRight="12dp" android:layout_gravity="right|center_vertical" - android:progressDrawable="@drawable/photo_progress_chat" + android:progressDrawable="@drawable/progress_chat" android:id="@+id/chat_view_action_progress" android:max="100"/> diff --git a/TMessagesProj/src/main/res/layout/chat_outgoing_video_layout.xml b/TMessagesProj/src/main/res/layout/chat_outgoing_video_layout.xml index 44a8c978b..ddd7ccc5c 100644 --- a/TMessagesProj/src/main/res/layout/chat_outgoing_video_layout.xml +++ b/TMessagesProj/src/main/res/layout/chat_outgoing_video_layout.xml @@ -31,7 +31,7 @@ android:layout_width="fill_parent" android:layout_height="3dp" android:layout_gravity="right|center_vertical" - android:progressDrawable="@drawable/photo_progress_chat" + android:progressDrawable="@drawable/progress_chat" style="?android:attr/progressBarStyleHorizontal" android:progress="50" android:layout_marginLeft="36dp" diff --git a/TMessagesProj/src/main/res/values-es/strings.xml b/TMessagesProj/src/main/res/values-es/strings.xml index 32dbcbfde..352603dfd 100644 --- a/TMessagesProj/src/main/res/values-es/strings.xml +++ b/TMessagesProj/src/main/res/values-es/strings.xml @@ -24,20 +24,20 @@ Ingresa tu nombre y apellidos Nombre (requerido) - Apellido/s (opcional) + Apellido(s) (opcional) Cancelar registro Chats Buscar - Mensajes nuevos + Nuevo mensaje Ajustes Contactos Nuevo grupo ayer Sin resultados No tienes conversaciones todavía... - Empieza a chatear presionando el\nbotón de componer en la esquina superior\nderecha o ve a la sección de Contactos. + Empieza a chatear presionando el\nbotón de Nuevo mensaje en la esquina superior\nderecha o ve a la sección de Contactos. Esperando red... Conectando... Actualizando... @@ -170,9 +170,9 @@ INGRESA EL NOMBRE DEL GRUPO - Multimedia compartida + Fotos y vídeos Información del grupo - MULTIMEDIA COMPARTIDA + FOTOS Y VÍDEOS AJUSTES Añadir miembro Eliminar y salir del grupo @@ -210,11 +210,11 @@ Restablecer todas las notificaciones Tamaño del texto - Haz una pregunta + Hacer una pregunta Activar animaciones Desbloquear Mantén pulsado un usuario para desbloquearlo - No hay usuarios bloqueados aún + No hay usuarios bloqueados TU NÚMERO DE TELÉFONO NOTIFICACIONES DE MENSAJES Alerta @@ -239,7 +239,7 @@ SOPORTE Fondo de chat MENSAJES - Enviar con enter + Enviar con ‘Enter’ Cerrar todas las otras sesiones DESCARGA AUTOMÁTICA DE FOTOS Grupos