From 5d8c19219f3f9129b06d81abb190b0ace1936f18 Mon Sep 17 00:00:00 2001 From: fidojones Date: Thu, 13 Feb 2014 21:48:35 +0100 Subject: [PATCH] Sync with new version 1.3.21 --- TMessagesProj/src/main/AndroidManifest.xml | 8 +- .../java/org/telegram/TL/TLClassStore.java | 1 + .../src/main/java/org/telegram/TL/TLRPC.java | 53 +- .../telegram/messenger/BackgroundService.java | 61 + .../messenger/ConnectionsManager.java | 69 +- .../messenger/ConnectionsManager2.java | 2670 +++++++++++++++++ .../messenger/ContactsController.java | 261 +- .../org/telegram/messenger/DispatchQueue.java | 14 +- .../messenger/ExportAuthorizationAction.java | 4 +- .../telegram/messenger/FileLoadOperation.java | 48 +- .../org/telegram/messenger/FileLoader.java | 17 +- .../messenger/GcmBroadcastReceiver.java | 45 +- .../org/telegram/messenger/GcmService.java | 42 + .../messenger/MessagesController.java | 229 +- .../telegram/messenger/MessagesStorage.java | 28 +- .../telegram/messenger/SerializedData.java | 140 +- .../org/telegram/messenger/TcpConnection.java | 25 +- .../org/telegram/messenger/UserConfig.java | 8 +- .../org/telegram/messenger/Utilities.java | 10 +- .../org/telegram/objects/MessageObject.java | 6 +- .../org/telegram/ui/ApplicationLoader.java | 5 + .../java/org/telegram/ui/Cells/BaseCell.java | 55 - .../telegram/ui/Cells/ChatMessageCell.java | 26 + .../org/telegram/ui/Cells/ChatOrUserCell.java | 2 +- .../org/telegram/ui/Cells/DialogCell.java | 18 +- .../java/org/telegram/ui/ChatActivity.java | 421 +-- .../org/telegram/ui/ContactsActivity.java | 64 +- .../org/telegram/ui/GalleryImageViewer.java | 22 +- .../java/org/telegram/ui/LaunchActivity.java | 4 +- .../telegram/ui/LoginActivityPhoneView.java | 2 + .../org/telegram/ui/PhotoCropActivity.java | 381 +++ .../ui/SettingsWallpapersActivity.java | 6 +- .../org/telegram/ui/UserProfileActivity.java | 14 +- .../org/telegram/ui/Views/AvatarUpdater.java | 79 +- .../org/telegram/ui/Views/LayoutListView.java | 12 +- .../java/org/telegram/ui/Views/SeekBar.java | 135 + .../src/main/res/drawable-hdpi/ic_send.png | Bin 703 -> 591 bytes .../res/drawable-hdpi/ic_send_disabled.png | Bin 725 -> 599 bytes .../src/main/res/drawable-hdpi/mic.png | Bin 0 -> 602 bytes .../main/res/drawable-hdpi/mic_pressed.png | Bin 0 -> 581 bytes .../src/main/res/drawable-hdpi/pause1.png | Bin 0 -> 175 bytes .../main/res/drawable-hdpi/pause1_pressed.png | Bin 0 -> 175 bytes .../src/main/res/drawable-hdpi/pause2.png | Bin 0 -> 175 bytes .../main/res/drawable-hdpi/pause2_pressed.png | Bin 0 -> 175 bytes .../src/main/res/drawable-hdpi/play1.png | Bin 0 -> 441 bytes .../main/res/drawable-hdpi/play1_pressed.png | Bin 0 -> 440 bytes .../src/main/res/drawable-hdpi/play2.png | Bin 0 -> 439 bytes .../main/res/drawable-hdpi/play2_pressed.png | Bin 0 -> 439 bytes .../src/main/res/drawable-hdpi/player1.png | Bin 0 -> 687 bytes .../res/drawable-hdpi/player1_pressed.png | Bin 0 -> 1210 bytes .../src/main/res/drawable-hdpi/player2.png | Bin 0 -> 676 bytes .../res/drawable-hdpi/player2_pressed.png | Bin 0 -> 1250 bytes .../src/main/res/drawable-hdpi/rec.png | Bin 0 -> 331 bytes .../src/main/res/drawable-hdpi/slidearrow.png | Bin 0 -> 420 bytes .../src/main/res/drawable-hdpi/tooltip.png | Bin 0 -> 367 bytes .../src/main/res/drawable-ldpi/ic_send.png | Bin 418 -> 343 bytes .../res/drawable-ldpi/ic_send_disabled.png | Bin 420 -> 344 bytes .../src/main/res/drawable-ldpi/mic.png | Bin 0 -> 359 bytes .../main/res/drawable-ldpi/mic_pressed.png | Bin 0 -> 356 bytes .../src/main/res/drawable-ldpi/pause1.png | Bin 0 -> 155 bytes .../main/res/drawable-ldpi/pause1_pressed.png | Bin 0 -> 157 bytes .../src/main/res/drawable-ldpi/pause2.png | Bin 0 -> 157 bytes .../main/res/drawable-ldpi/pause2_pressed.png | Bin 0 -> 157 bytes .../src/main/res/drawable-ldpi/play1.png | Bin 0 -> 285 bytes .../main/res/drawable-ldpi/play1_pressed.png | Bin 0 -> 289 bytes .../src/main/res/drawable-ldpi/play2.png | Bin 0 -> 285 bytes .../main/res/drawable-ldpi/play2_pressed.png | Bin 0 -> 287 bytes .../src/main/res/drawable-ldpi/player1.png | Bin 0 -> 368 bytes .../res/drawable-ldpi/player1_pressed.png | Bin 0 -> 532 bytes .../src/main/res/drawable-ldpi/player2.png | Bin 0 -> 368 bytes .../res/drawable-ldpi/player2_pressed.png | Bin 0 -> 538 bytes .../src/main/res/drawable-ldpi/rec.png | Bin 0 -> 223 bytes .../src/main/res/drawable-ldpi/slidearrow.png | Bin 0 -> 261 bytes .../src/main/res/drawable-ldpi/tooltip.png | Bin 0 -> 223 bytes .../src/main/res/drawable-mdpi/ic_send.png | Bin 524 -> 309 bytes .../res/drawable-mdpi/ic_send_disabled.png | Bin 531 -> 381 bytes .../src/main/res/drawable-mdpi/mic.png | Bin 0 -> 431 bytes .../main/res/drawable-mdpi/mic_pressed.png | Bin 0 -> 402 bytes .../src/main/res/drawable-mdpi/pause1.png | Bin 0 -> 163 bytes .../main/res/drawable-mdpi/pause1_pressed.png | Bin 0 -> 163 bytes .../src/main/res/drawable-mdpi/pause2.png | Bin 0 -> 163 bytes .../main/res/drawable-mdpi/pause2_pressed.png | Bin 0 -> 163 bytes .../src/main/res/drawable-mdpi/play1.png | Bin 0 -> 308 bytes .../main/res/drawable-mdpi/play1_pressed.png | Bin 0 -> 308 bytes .../src/main/res/drawable-mdpi/play2.png | Bin 0 -> 309 bytes .../main/res/drawable-mdpi/play2_pressed.png | Bin 0 -> 308 bytes .../src/main/res/drawable-mdpi/player1.png | Bin 0 -> 516 bytes .../res/drawable-mdpi/player1_pressed.png | Bin 0 -> 828 bytes .../src/main/res/drawable-mdpi/player2.png | Bin 0 -> 503 bytes .../res/drawable-mdpi/player2_pressed.png | Bin 0 -> 845 bytes .../src/main/res/drawable-mdpi/rec.png | Bin 0 -> 278 bytes .../src/main/res/drawable-mdpi/slidearrow.png | Bin 0 -> 242 bytes .../src/main/res/drawable-mdpi/tooltip.png | Bin 0 -> 285 bytes .../src/main/res/drawable-xhdpi/ic_send.png | Bin 844 -> 748 bytes .../res/drawable-xhdpi/ic_send_disabled.png | Bin 842 -> 744 bytes .../src/main/res/drawable-xhdpi/mic.png | Bin 0 -> 722 bytes .../main/res/drawable-xhdpi/mic_pressed.png | Bin 0 -> 666 bytes .../src/main/res/drawable-xhdpi/pause1.png | Bin 0 -> 192 bytes .../res/drawable-xhdpi/pause1_pressed.png | Bin 0 -> 193 bytes .../src/main/res/drawable-xhdpi/pause2.png | Bin 0 -> 194 bytes .../res/drawable-xhdpi/pause2_pressed.png | Bin 0 -> 191 bytes .../src/main/res/drawable-xhdpi/play1.png | Bin 0 -> 492 bytes .../main/res/drawable-xhdpi/play1_pressed.png | Bin 0 -> 492 bytes .../src/main/res/drawable-xhdpi/play2.png | Bin 0 -> 492 bytes .../main/res/drawable-xhdpi/play2_pressed.png | Bin 0 -> 493 bytes .../src/main/res/drawable-xhdpi/player1.png | Bin 0 -> 858 bytes .../res/drawable-xhdpi/player1_pressed.png | Bin 0 -> 1470 bytes .../src/main/res/drawable-xhdpi/player2.png | Bin 0 -> 844 bytes .../res/drawable-xhdpi/player2_pressed.png | Bin 0 -> 1482 bytes .../src/main/res/drawable-xhdpi/rec.png | Bin 0 -> 439 bytes .../main/res/drawable-xhdpi/slidearrow.png | Bin 0 -> 350 bytes .../src/main/res/drawable-xhdpi/tooltip.png | Bin 0 -> 466 bytes .../src/main/res/drawable-xxhdpi/ic_send.png | Bin 1282 -> 1053 bytes .../res/drawable-xxhdpi/ic_send_disabled.png | Bin 1310 -> 1083 bytes .../src/main/res/drawable-xxhdpi/mic.png | Bin 0 -> 1090 bytes .../main/res/drawable-xxhdpi/mic_pressed.png | Bin 0 -> 996 bytes .../src/main/res/drawable-xxhdpi/pause1.png | Bin 0 -> 263 bytes .../res/drawable-xxhdpi/pause1_pressed.png | Bin 0 -> 262 bytes .../src/main/res/drawable-xxhdpi/pause2.png | Bin 0 -> 261 bytes .../res/drawable-xxhdpi/pause2_pressed.png | Bin 0 -> 261 bytes .../src/main/res/drawable-xxhdpi/play1.png | Bin 0 -> 644 bytes .../res/drawable-xxhdpi/play1_pressed.png | Bin 0 -> 643 bytes .../src/main/res/drawable-xxhdpi/play2.png | Bin 0 -> 644 bytes .../res/drawable-xxhdpi/play2_pressed.png | Bin 0 -> 644 bytes .../src/main/res/drawable-xxhdpi/player1.png | Bin 0 -> 1312 bytes .../res/drawable-xxhdpi/player1_pressed.png | Bin 0 -> 2355 bytes .../src/main/res/drawable-xxhdpi/player2.png | Bin 0 -> 1290 bytes .../res/drawable-xxhdpi/player2_pressed.png | Bin 0 -> 2436 bytes .../src/main/res/drawable-xxhdpi/rec.png | Bin 0 -> 573 bytes .../main/res/drawable-xxhdpi/slidearrow.png | Bin 0 -> 416 bytes .../src/main/res/drawable-xxhdpi/tooltip.png | Bin 0 -> 698 bytes .../main/res/drawable/mic_button_states.xml | 6 + .../src/main/res/drawable/pause1_states.xml | 6 + .../src/main/res/drawable/pause2_states.xml | 6 + .../main/res/drawable/photo_progress_chat.xml | 10 +- .../src/main/res/drawable/play1_states.xml | 6 + .../src/main/res/drawable/play2_states.xml | 6 + .../src/main/res/drawable/progress_chat.xml | 14 + .../main/res/drawable/send_button_states.xml | 4 +- .../chat_group_incoming_document_layout.xml | 2 +- .../chat_group_incoming_video_layout.xml | 2 +- .../main/res/layout/chat_header_layout.xml | 1 - .../layout/chat_incoming_document_layout.xml | 2 +- .../res/layout/chat_incoming_video_layout.xml | 2 +- .../src/main/res/layout/chat_layout.xml | 18 +- .../res/layout/chat_outgoing_audio_layout.xml | 91 + .../layout/chat_outgoing_document_layout.xml | 2 +- .../res/layout/chat_outgoing_video_layout.xml | 2 +- .../main/res/layout/settings_name_layout.xml | 2 - .../src/main/res/values-es/strings.xml | 25 +- TMessagesProj/src/main/res/values/strings.xml | 9 - 151 files changed, 4500 insertions(+), 701 deletions(-) create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/BackgroundService.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/ConnectionsManager2.java create mode 100644 TMessagesProj/src/main/java/org/telegram/messenger/GcmService.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/PhotoCropActivity.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Views/SeekBar.java create mode 100755 TMessagesProj/src/main/res/drawable-hdpi/mic.png create mode 100755 TMessagesProj/src/main/res/drawable-hdpi/mic_pressed.png create mode 100755 TMessagesProj/src/main/res/drawable-hdpi/pause1.png create mode 100755 TMessagesProj/src/main/res/drawable-hdpi/pause1_pressed.png create mode 100755 TMessagesProj/src/main/res/drawable-hdpi/pause2.png create mode 100755 TMessagesProj/src/main/res/drawable-hdpi/pause2_pressed.png create mode 100755 TMessagesProj/src/main/res/drawable-hdpi/play1.png create mode 100755 TMessagesProj/src/main/res/drawable-hdpi/play1_pressed.png create mode 100755 TMessagesProj/src/main/res/drawable-hdpi/play2.png create mode 100755 TMessagesProj/src/main/res/drawable-hdpi/play2_pressed.png create mode 100755 TMessagesProj/src/main/res/drawable-hdpi/player1.png create mode 100755 TMessagesProj/src/main/res/drawable-hdpi/player1_pressed.png create mode 100755 TMessagesProj/src/main/res/drawable-hdpi/player2.png create mode 100755 TMessagesProj/src/main/res/drawable-hdpi/player2_pressed.png create mode 100755 TMessagesProj/src/main/res/drawable-hdpi/rec.png create mode 100755 TMessagesProj/src/main/res/drawable-hdpi/slidearrow.png create mode 100755 TMessagesProj/src/main/res/drawable-hdpi/tooltip.png create mode 100755 TMessagesProj/src/main/res/drawable-ldpi/mic.png create mode 100755 TMessagesProj/src/main/res/drawable-ldpi/mic_pressed.png create mode 100755 TMessagesProj/src/main/res/drawable-ldpi/pause1.png create mode 100755 TMessagesProj/src/main/res/drawable-ldpi/pause1_pressed.png create mode 100755 TMessagesProj/src/main/res/drawable-ldpi/pause2.png create mode 100755 TMessagesProj/src/main/res/drawable-ldpi/pause2_pressed.png create mode 100755 TMessagesProj/src/main/res/drawable-ldpi/play1.png create mode 100755 TMessagesProj/src/main/res/drawable-ldpi/play1_pressed.png create mode 100755 TMessagesProj/src/main/res/drawable-ldpi/play2.png create mode 100755 TMessagesProj/src/main/res/drawable-ldpi/play2_pressed.png create mode 100755 TMessagesProj/src/main/res/drawable-ldpi/player1.png create mode 100755 TMessagesProj/src/main/res/drawable-ldpi/player1_pressed.png create mode 100755 TMessagesProj/src/main/res/drawable-ldpi/player2.png create mode 100755 TMessagesProj/src/main/res/drawable-ldpi/player2_pressed.png create mode 100755 TMessagesProj/src/main/res/drawable-ldpi/rec.png create mode 100755 TMessagesProj/src/main/res/drawable-ldpi/slidearrow.png create mode 100755 TMessagesProj/src/main/res/drawable-ldpi/tooltip.png create mode 100755 TMessagesProj/src/main/res/drawable-mdpi/mic.png create mode 100755 TMessagesProj/src/main/res/drawable-mdpi/mic_pressed.png create mode 100755 TMessagesProj/src/main/res/drawable-mdpi/pause1.png create mode 100755 TMessagesProj/src/main/res/drawable-mdpi/pause1_pressed.png create mode 100755 TMessagesProj/src/main/res/drawable-mdpi/pause2.png create mode 100755 TMessagesProj/src/main/res/drawable-mdpi/pause2_pressed.png create mode 100755 TMessagesProj/src/main/res/drawable-mdpi/play1.png create mode 100755 TMessagesProj/src/main/res/drawable-mdpi/play1_pressed.png create mode 100755 TMessagesProj/src/main/res/drawable-mdpi/play2.png create mode 100755 TMessagesProj/src/main/res/drawable-mdpi/play2_pressed.png create mode 100755 TMessagesProj/src/main/res/drawable-mdpi/player1.png create mode 100755 TMessagesProj/src/main/res/drawable-mdpi/player1_pressed.png create mode 100755 TMessagesProj/src/main/res/drawable-mdpi/player2.png create mode 100755 TMessagesProj/src/main/res/drawable-mdpi/player2_pressed.png create mode 100755 TMessagesProj/src/main/res/drawable-mdpi/rec.png create mode 100755 TMessagesProj/src/main/res/drawable-mdpi/slidearrow.png create mode 100755 TMessagesProj/src/main/res/drawable-mdpi/tooltip.png create mode 100755 TMessagesProj/src/main/res/drawable-xhdpi/mic.png create mode 100755 TMessagesProj/src/main/res/drawable-xhdpi/mic_pressed.png create mode 100755 TMessagesProj/src/main/res/drawable-xhdpi/pause1.png create mode 100755 TMessagesProj/src/main/res/drawable-xhdpi/pause1_pressed.png create mode 100755 TMessagesProj/src/main/res/drawable-xhdpi/pause2.png create mode 100755 TMessagesProj/src/main/res/drawable-xhdpi/pause2_pressed.png create mode 100755 TMessagesProj/src/main/res/drawable-xhdpi/play1.png create mode 100755 TMessagesProj/src/main/res/drawable-xhdpi/play1_pressed.png create mode 100755 TMessagesProj/src/main/res/drawable-xhdpi/play2.png create mode 100755 TMessagesProj/src/main/res/drawable-xhdpi/play2_pressed.png create mode 100755 TMessagesProj/src/main/res/drawable-xhdpi/player1.png create mode 100755 TMessagesProj/src/main/res/drawable-xhdpi/player1_pressed.png create mode 100755 TMessagesProj/src/main/res/drawable-xhdpi/player2.png create mode 100755 TMessagesProj/src/main/res/drawable-xhdpi/player2_pressed.png create mode 100755 TMessagesProj/src/main/res/drawable-xhdpi/rec.png create mode 100755 TMessagesProj/src/main/res/drawable-xhdpi/slidearrow.png create mode 100755 TMessagesProj/src/main/res/drawable-xhdpi/tooltip.png create mode 100755 TMessagesProj/src/main/res/drawable-xxhdpi/mic.png create mode 100755 TMessagesProj/src/main/res/drawable-xxhdpi/mic_pressed.png create mode 100755 TMessagesProj/src/main/res/drawable-xxhdpi/pause1.png create mode 100755 TMessagesProj/src/main/res/drawable-xxhdpi/pause1_pressed.png create mode 100755 TMessagesProj/src/main/res/drawable-xxhdpi/pause2.png create mode 100755 TMessagesProj/src/main/res/drawable-xxhdpi/pause2_pressed.png create mode 100755 TMessagesProj/src/main/res/drawable-xxhdpi/play1.png create mode 100755 TMessagesProj/src/main/res/drawable-xxhdpi/play1_pressed.png create mode 100755 TMessagesProj/src/main/res/drawable-xxhdpi/play2.png create mode 100755 TMessagesProj/src/main/res/drawable-xxhdpi/play2_pressed.png create mode 100755 TMessagesProj/src/main/res/drawable-xxhdpi/player1.png create mode 100755 TMessagesProj/src/main/res/drawable-xxhdpi/player1_pressed.png create mode 100755 TMessagesProj/src/main/res/drawable-xxhdpi/player2.png create mode 100755 TMessagesProj/src/main/res/drawable-xxhdpi/player2_pressed.png create mode 100755 TMessagesProj/src/main/res/drawable-xxhdpi/rec.png create mode 100755 TMessagesProj/src/main/res/drawable-xxhdpi/slidearrow.png create mode 100755 TMessagesProj/src/main/res/drawable-xxhdpi/tooltip.png create mode 100644 TMessagesProj/src/main/res/drawable/mic_button_states.xml create mode 100644 TMessagesProj/src/main/res/drawable/pause1_states.xml create mode 100644 TMessagesProj/src/main/res/drawable/pause2_states.xml create mode 100644 TMessagesProj/src/main/res/drawable/play1_states.xml create mode 100644 TMessagesProj/src/main/res/drawable/play2_states.xml create mode 100644 TMessagesProj/src/main/res/drawable/progress_chat.xml create mode 100644 TMessagesProj/src/main/res/layout/chat_outgoing_audio_layout.xml 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..f111120c6 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 switchToNextPort = wasConnected && !hasSomeDataSinceLastConnect && timedout; 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 || switchToNextPort) { 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/BaseCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/BaseCell.java index 3b9b7bacf..4c17a2699 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/BaseCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/BaseCell.java @@ -10,18 +10,10 @@ package org.telegram.ui.Cells; import android.content.Context; import android.graphics.drawable.Drawable; -import android.os.Build; -import android.text.TextUtils; import android.util.AttributeSet; import android.view.View; -import android.view.accessibility.AccessibilityEvent; -import android.view.accessibility.AccessibilityNodeInfo; - -import org.telegram.messenger.R; public class BaseCell extends View { - private CharSequence currentNameMessage; - public BaseCell(Context context) { super(context); } @@ -41,51 +33,4 @@ public class BaseCell extends View { protected void setDrawableBounds(Drawable drawable, int x, int y, int w, int h) { drawable.setBounds(x, y, x + w, y + h); } - - public void tryInstallAccessibilityDelegate() { - if (Build.VERSION.SDK_INT < 14) { - return; - } - - setAccessibilityDelegate(new AccessibilityDelegate() { - @Override - public void onInitializeAccessibilityNodeInfo(View host,AccessibilityNodeInfo info) { - super.onInitializeAccessibilityNodeInfo(host,info); - // We called the super implementation to let super classes set - // appropriate info properties. Then we add our properties - // (checkable and checked) which are not supported by a super class. - // Very often you will need to add only the text on the custom view. - CharSequence text = getTextAccessibility(); - if (!TextUtils.isEmpty(text)) { - info.setText(text); - } - } - - @Override - public void onPopulateAccessibilityEvent(View host,AccessibilityEvent event) { - super.onPopulateAccessibilityEvent(host,event); - // We called the super implementation to populate its text to the - // event. Then we add our text not present in a super class. - // Very often you will need to add only the text on the custom view. - CharSequence text = getTextAccessibility(); - if (!TextUtils.isEmpty(text)) { - event.getText().add(text); - } - } - }); - } - - public CharSequence getTextAccessibility() { - if (!TextUtils.isEmpty(currentNameMessage)) { - return currentNameMessage; - }else{ - return getResources().getString(R.string.ContactUnAllocated); - } - } - - public void setTextAccessibility(CharSequence text){ - - currentNameMessage = text; - } - } 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 4dac35912..23a1a1ffe 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogCell.java @@ -251,7 +251,6 @@ public class DialogCell extends BaseCell { requestLayout(); } - tryInstallAccessibilityDelegate(); invalidate(); } @@ -395,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); } } } @@ -639,9 +642,6 @@ public class DialogCell extends BaseCell { CharSequence messageStringFinal = TextUtils.ellipsize(messageString, currentMessagePaint, messageWidth - Utilities.dp(12), TextUtils.TruncateAt.END); messageLayout = new StaticLayout(messageStringFinal, currentMessagePaint, messageWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); - //Set string for Accessibility events to speak contact list - setTextAccessibility(nameStringFinal+" "+getResources().getString(R.string.LastMessage)+": "+messageString); - double widthpx = 0; float left = 0; if (Utilities.isRTL) { 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 da37f80332643da060d9ec4b60b7749b39e130b8..50e63ae1ec05da8c71fb04c6e925ca40575891a2 100755 GIT binary patch delta 548 zcmV+<0^9w+1sp(f9CN9>-3*KhC{<`P%Ne_jo?%oaa90p2Xx%d)l(BGF*XcR?JGm zpYR-f0bj%OaRWTVUAit1NCRGoe+%FTc9eFxEawEW7&U-YU2|W8oWZwIfw%xppXc%f zat|-XIRmPu;8OxwHVM#%-+c6wASducSdb+9Uk}iKfrb3tCd#aVGJH+ z)le!8XIS>9;2~Ofzv{qS@PQ5>=qN`h@$%GGrZ%0fgy!9rqt9yYrIfZ|&9gb0A)Q+A zt_rXYul<#^2GpeKugVJ*pcr9rS?D%ln>TWR3`;zdk_E1$``i=C-fvQu@CN;AC6qni zglaTmPo0P?uDPa}>bFbBx89ZMe3w&}azBaWk)U`I2X mf_LLQoC?b38S9_)E5HD$N?*8k;qJWv0000QAA2B?cQu+V_70yM7K*< z-L#}3wwuJRE+Qf#BBJ-@nVgQj2NVpd8UP+n_GsJ^3x*vwh@UfUc7> zHUWc1Q3u_&1!@A&RYn2b2Dni`$Iwe>5Xq(qP!+IlxO`ktj_6)kP!;f*fBa;j&biB1 z0b0N+5DL&l9r}Uhf`aORjwxBxT1$o0#E&72r39_t% zcF{!b_XU&WZq&>m&P`xm?86+%8Z$KU@N`ur=V{t*bpjZs8AfqDg5@TS7huicrTxU) zj|FJ}Xu@OqR--L25IX>Se-Dy=*=A5Z^+=bRPMi9bVjXabd==Avgri&m*iVz{fU_~c zamtSX_M%_(ieOaY`SXBWB(T?ZH|c;g5r8pF5pZvQ8+WNK40M-dt^wYf-G`GC=)Zk~i@gnWQq5wo?retBV*UF-Cbc$T@1v5iv@7)ZYoZ vvLO;6iK(K6+R9@+ON=D8n!_TY`W9dST%n9J&R@_k00000NkvXXu0mjfRgfxr 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 93b2f1604a8f79afe64e0e4f01fa9e5c6ffae4b7..4473d1c6f36d8a3ce2354d4313981fc9e42166f0 100755 GIT binary patch delta 557 zcmV+|0@D4}1=j>2iBL{Q4GJ0x0000DNk~Le0000W0000W2nGNE0CReJ^pPPqe*x)9 zL_t(|+QgU9M?+B@$M4n^BO*q`h%q8Y#QuPYo_dO&dW!uGQH-poy%Z@@r0HetCE9B* z#WbafrWA3Bh!GK4-ygrr&#|-JyL;~K$JchwJ;(2J&iS3+IVV=BRAwy8DnccwW<_jq z=nI;IE}$!DK5BqxsLkaZgWNz1e^CMaLJg&!mgSs57Q+T0t82a!$Qg7S7KjVb=+iFC zAotKxlrx~(G<3=!%O(Ndpm!hr2;>BM2nrGx|LX(vpJI?lXeB5>Bfvm1(4hbs8U*0l zz>>NkPhLSJz@5S1o)jRf(6ASP56+5~VURsunyw&mrCbUr;kh6$P+o$>e{dRh>o5V0 zi)=`igi<2<6VM2+yI*slE$G1R(ZKP!J7|<+9C%r-D{@`80d7-PwKaR2MxWMvODJ`t znzk99A)U3LT@_#*TI&_H2CT``U#5ZzkPp#0E#)Rum6Z}8B?8Z+QGzSzu6wp}_M5az zXoG*XW-DjD39IplJ*9RDe~=64xXNqn>rgW>17(it<{+JI5r9b_{pccl%#K?@rp*PI z_1OLgI%3DKCIZIxxC6c^Z?j{^bz`3z1zX$z0000;lZe+K&l52u*Yp7No;*+Phyu`Q;##iuO++*_P#5sZ$2~46M|9CPs0&yjzxceji@Xld zC34Cppx-F!psTh(O#r$|DWIzWHwx$&dg&A*d1nGt1uPm)9~YD(x)Bsqe+7IbKUm0f zuJQ$dZekV)1ZW};8-dRI1=Rr^VP8oFbh}U}^u{HEUZDJqza_}Jpsm?#R{hPD_emZi zcZLMoMjmI_a=F|`zD}ppukOhNb<~X>Fv>52oax805%h~)=p$LfhB_YZt`5mL>b9%R z00t?BA?y!gx=G>%1fn(Cf5dZm`7tdG0F8Kb-)gi48e#`vZ+`Mr)@f8vJcdghPMi8Q z#5&*@`7)yQ2uJwFq}`6pHRCwC# zSI6UE3XJF2NTu@F< z7xWWY7v{Fwi$KIeV4@cR8yoy>0nr!e3-kr_7Dm_Xwo`OO=O;)x=btW7+k)raPoTx7 z#`}NWLf~1$(UJoEOpUV77Zw8N8jhM2sAvw3eV}1LE^`hv92F_xvIiMVF+>$52d05H zA95K>Q?8(~85Vb?KnZBlgJ~ek%C-y_1MLHtGjLbzqOb{^dIHjJ+0Cs%Q!g8CtYx?}VBEX;(aZ%Gn5Q=gv)Voc z_8|1CAs&U>1$NlE{2^BWxKRb9tnw$fdO$0g~UulN3uRd+BStHh9A(?G@EZ|Kmh+ oO#VWl-lbC$9qf<5v7Z7A0NW0ksT~_cBme*a07*qoM6N<$g2dVXlK=n! literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..3cf43e04bd343951dac40e1be5bad746301640fe GIT binary patch literal 581 zcmV-L0=oT)P)+WXIVIO=jzIpHa#y7JwFEm|j87?gWEO1-{nqu&@J>i%% z;(|B{oB+$3{|?v!8cxaK0puB=-iO?vuRe49n(-?jN^%N}ImC#$Q-~z|2;>Klt0H+n z0_%o*Tk~5Yw>If_lik|rUkez4Kp+qZIKKxy<#%Wpq_|ys|Dr@)4?Lev0&VSXm)7(k z@S>DQhNCJ3OvSMYM3lrV@Zmr%=CWvA zS}ae59MVi7PzEeIW`Ud%PytfFg|_Kk`cfdTDE=Hdgjtv?%f4tAIOF(;J|w^<**o2>qDMqjyyp%tiGgw2RlHA<2VxvK+Ite zVjwRtHcnrMT;ErN)|;*Z=fJpDZSK;K>|{eF-oCSiN+H T<;0?Z00000NkvXXu0mjfl6UgJ literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..30e945f3165d96a6a7f2c94331b9d55363e30190 GIT binary patch literal 175 zcmeAS@N?(olHy`uVBq!ia0vp^5}1{rUgjo>`Ysn7Nmc z+ekgJRweAc4oA$n4&ONvUroLrT*10ntS8DK3&wELNs#%(tKY!D%-|8rXLz+Zc^1$x N22WQ%mvv4FO#l!xG<5&~ literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..0053b7b035afbb7dd2f76da9351bfe7b50a4c305 GIT binary patch literal 175 zcmeAS@N?(olHy`uVBq!ia0vp^5}1{rUgjo>`Ysn7Nmc z+vs@lJmIkSIsUhfclgec_-gX~;0o5oVm(m?Sulo^PJ+xQUi}6JW(J#HK0}E;D?S1Z OWAJqKb6Mw<&;$T|_%?w6 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..f96f878e98c6a2f194a0093690d5177920c8780e GIT binary patch literal 175 zcmeAS@N?(olHy`uVBq!ia0vp^5}1{rUgjo>`Ysn7Nmc z+vs@aE#o!!ZcbM{+TlA#;;YH`gDY4Ui}geqWWg9tItenLc=a0?m>D8!`3w~}1{rUgjo>`Ysn7Nmc z+sJ+ON3F2;F{`hq9Z~b^shagW;Yw2=x0|lSRv1H3%z*D_o47**BZJRfK0}Q!p&3BK O7(8A5T-G@yGywo+=rz3n literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..8bb953bcf48a18b787b5b9674d8974d1c626bac4 GIT binary patch literal 441 zcmV;q0Y?6bP)N~1izyOVpOlbUo;)#vg7Qg^M5Q9?MRUi(eg#|F60>tZp_y7m#FR;RAGV z3W#%ozBxrLAD{y>AU+B7%^V<>poIl6kO0j)3@kJ-d?HFyU#QxOQf z1L7mNn$Lx$`dF})jApE(r6$yrBfOs7c9{^$l zT37%B_CS0di01&Y1R=$Yz>M~vf;jvF#2rA~2h4EaspSJ?zyriBKzzeLSpe1Hy4 z0dX$SH>arO19V^p#3zBinFGWUw6FjM5}ywguOq2JfI|DguFb zK%51{dgz8z>VscEJOxx)0S(4kS&?hOdLS+X;yZ+DG*T_N0K^4Ae305@(F-6>0b)Z^ z3@641pz@^;THbsiCoJ(<-WS|@{C8V$te)G{3A19+JZ4Rfjj ikOivHR6-K~5MTgT1WpdN>XiQg00008UDjMx h)?ih3i5E=-7yx6}OysI+4~+l-002ovPDHLkV1jF@vi1M~ literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..08e691986291dbc8fde8c085c4f24c65f6f946b4 GIT binary patch literal 439 zcmV;o0Z9IdP)179|lfq(1APH^kLw% z1CP*x+^mmN9JEn_9uDCe>KwQqtpxwI0$1=FTnzSnB#5dHhotFiC5UPp9!S%IoDT!1 zeK|WO%V`E}ID?NQTP!nap2$=6PPTtqhN4z+m*8)v%bKgo h8sue{c+psZ0RYLJO<=`=d?o+@002ovPDHLkV1l3Gx1<07 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..6ec1a5d281f4a1ccf5986f08f79126ec9bef9278 GIT binary patch literal 687 zcmV;g0#N;lP)nA_7PX zO)C_KnxHb2hYHXMR1DK^!V-c$-UoF-%`ZGkZqGr#pkpUMfayl_5vr4f0@TLphqBOl zRe%7Z& z|Ekl)O$#rHmVHJX4Cl2AG2a`1ge%8qy`oz2Tke+xuO~UUuY;y6E%MA&&HPiCM=N_X zr0%CIs1GkXq5R5s{@-Z0JSRfdxQjbO`B3ZRv>Yh4ckDi>7Ug)kqYm3bGcVg%G)72}Cu zegv)Jpc0m#vRt4?nLbLk-y}yOCFu=NxCMsVGs3&S>;!oL7D_&~=nP-~S)_?|>cz7y#P! VxnE#JB>n&Z002ovPDHLkV1jlWF#7-i literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..f5698eb118e03763c232b830be19d3a847dd8495 GIT binary patch literal 1210 zcmV;r1V#IaP)Nh!Q4v(cKb4Bb4-x!O@S_z( zs-R#M7c5m#5$l2lam9ryYOGb8WoDk|#YuXTChbcz!3T$A-n^MPbKkw^-aC9zLpl4O z<4X18xMODq_bLG<10G;J5Cq-;9Y8Datv@$Smyk5)LZA{D(Z|}Cz*XQ9@WpOI(h@s> z(lp4AwXg}O2hN#Af%kS0+5)WWG0T~sanXj~u+YQ@&X|jtd>9kVhhItDOIEK1sS#beDBkyoC)CzKLg2U{Ezb*4>(pa!N*uY&4;pgM#(UX%qS5XewwyI== zDq*;_g=#UzNyoxL1Hg zMb9we%cRxR%qu>VqfwNQFJ?;4x|D8aBq0-hj=|?D8ks)JM+up6ndm=`D50O-R%E$K zSH|b2c!za}7RBf1k^g>5=q>Sq;fjje2=*;Wgzq90{;FE+^P%ME9S!?dvS^%g8Ym2I zg99&t&&>Q6_7K!OwM5K=jzZK;h1Ov^iv4y<=#!iTWW`s=yPU<)i4RIInICFG-P4q= zuYk}La@d+oshi2-`Pr3e1dgs%l9`*y2%RG#J%)S$5hl0Z{flu4_xl)RErmp+h9vO0^Epa(jy*?&O`W8oX#h)OTT>rrrp>0P4ur zEkP8`vx^MU&4z?1KB!VtHvpH3iL13Ap6ZOYPuFs_AMS0WC6c2SoyT3(HfSF(1ej)7 zY96w9iSQZ?s&dfnz^gtv>6~WGU0S>Dl#gq^Z}sF>eDpK7bfx$pU6UPgd&5rL;z=`usU$AIMPCk zh;vK#j0i!Xr{rix7+eQn_YMUgf(bDxT*^q1A_ctJ&8LG>R9@RpIXB8sS#A_{_dA>vDUb;s0|XF1h9Fc1 zH9&7r0!l$w(5rP10YdzF57YrQ{_v>ClsI$@omv3`Oecl`sG9M(1GPx?Lfg=7QGfs< z0)GhV_PDxD(1e7F839R{F&QhS**qe>yK9p6!$pAkZhbQT^nu`=E(~23N=*o=)dB*H zSjv8j#duKHLn46v77KD46wm?c`GsAgo0Vl)E>U%B*wbFpBt26YmFFEfv`Wns)$kH4 z?E`F>7|l^STNXYoMKknB5v0NbUHb#DK^HEYS4IXLlvznfAg~gJH-J?Fmq%P4v!WH)d=?ZWhPL96ED{qm1LeS zXbSNZ%BH;^UJKF&^X(_8+`gsIsROlWN_K%Z?Eu=zZ(&uH`p_~=M%5dsfJE#0U=b*$ zidCQDBp|+E$5IIpnYE|g4*@Ff*4=rqcPN@IonAUdK#?#~!6OPTW2szYaMj*DHJ?<{WYKu0R{l0x0VEb%Uj6+0000< KMNUMnLSTZPxFB5s literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..879278c30e36f4b656072ffc13c8b51372fe7db4 GIT binary patch literal 1250 zcmV<81ReW{P)C?@=zodEEozZk=UX|jTRaZFNqoxW7sppGmrHn86YwhF1zrZyzNvoF)uBaP#drvXa^b!?7aj0 z0{je2m75Tk#3#VoBFMLxcpvBmPFJt2epn7d9|8ydw<@rRD2XGu%ZRf0h#5@Lvw9t_ zL0ma;KiRz>=$v^la}=b0S}dVgfWts5S<6U@bU_Iy*L*Md#_~OA7>1CHBwMwlwh`nu zn9CyY1xU4k)Yti*74mo)C-W^}y8xtc#aHb+;|X~FF2?9mGpXiuJl$dF#%i)W2vXbx z*!69>G7udEEzsLau zgO^H)HG(8)I8d+Tk4E|)tphn9y<34&n7rKP~$e1zJ}h&yMC{%Zf(N~8*|KE*fbW9^!*@A{B*kPnE}g zVw_+*n94TcPDh%($m-aTo5yhI;Y>1fkff#@3ANceekRJoW0du|J0NOCXqz zv9DZ8XqFgv7;0;xgc@yzk~r;(%sAV_vd`3P4^ECt&5ePJ!V@xmkrE1$q?vR@DC0oJ z8Y+9+oy+C?R*(|XbGALlVG)YjnOZjjuAWp_{&eDTXV|C;LS!1DghmOWdRK&2uzn^v z{IJZF?CDL@?FZrZt`f02tJXk5HRf~@ z#r`BE^q4OKb$nAQnrifgeUDs`YG4ESJ5a2xs4?|5G97k`)b`2LxVp8HhRZ9;teR~n zOBbC8owil0>2IZD>4r)XN<2+$1}V#aB2d?PCqnmtTbAoXZ5{k1=42V z_2Q#$YU)1V91(G6Y$DcKiu$0UKy)J7OQ@8Wxo zfy}R^_V&CNziHOo9XW=|3H*0$S>X9N@V)u5Aycp-De{9AuUUBU#YZ^>lFzskoK2NA%h02DU4W7K|OS z3*W>$)ChN!Gk?@ksOwrYgVncKP+&WQq57;Hsv^&s3&jNVn>`I2Gbgm|b-2^*YHaj? z{n65ZGd(#6OcctJ6y#hO3r){37_XS`$*RD-#E~tfAc)T8QJFv+(`pr^l$eSVVpupPEKY2kVufTO> z^{4M0a=4F}1}uNb6yIPW+u_{!Lw^$^Pe5asf*Io@O@|su&v!Zk>Iy5jc ZZ2F=4eAl!ahkzbs@O1TaS?83{1OOlNa4`S? literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..b04164901d6f00d064edfdbef085baa20db28900 GIT binary patch literal 420 zcmV;V0bBlwP)jNRfzo>bFEuSJ1O+$Nl&S@enC zf*{Zq;Y^`-v`(q*phD*kG^)Rw2B_zOUhO%i0U9V&qD>e22RfNb%{25?Wh|(x&^-Fk zOv9!g%vjJRno~$Jy|i_FI!#kK&|B-AHh`W(=PRXt%K|zU|NX?c$*}qp@c@m{0=lF0 z)exA}Cf9uqv^lLEo#-l)WS_g}3w1)76Zcv<2JpJZ>l`NCXl7~JBD!a>l_03_l?Pr9 zf)>1I!4EdvdLMzsP5VyfrKmpu@CD&eVS$eRtU^~~l;?RL9oOSu0R{l=kEP!_7_t5U O0000ra@ocD)4hB}-f* zN`mv#O3D+9QW+dm@{>{(JaZG%Q-e|yQz{EjrrIztFfw|&IEGZ*dUMO0?~nnHYoPU( z5=Ncozxv≤qt-g;-pujCmPl)R|C}HM4KtF^Q)+SD*5S#`ez_E8eyu!|%5At_Myp z&)tb$e1EBUasU1o*{>8!<3FsuC~3W1F4+I~7G10R?OPu6=UdOY_B~B)uitgQUFE;- zzka)m?X$Ci^}CO)f;u65_oUvL9r@KXXM;mC8?Tf}#)Sor_!+mDcbzJ-T5~F0eQ&yz z?X`KPe`lBcD=O=n*S+5B>$}7&fuZj=9aYi4WT)_ZQoci(rPFiulP7PcTiUu#RJYDN o>-lwa+rFbeZ!cce&%n$ut<7tK&5x_Ufg#4=>FVdQ&MBb@09~4!B>(^b literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-ldpi/ic_send.png b/TMessagesProj/src/main/res/drawable-ldpi/ic_send.png index f094ca9096b1ae7c31e91ffa2d461ffc52d4f790..9e921724d5e8a5dab1cb3e5dbebc47b8e0eb16f4 100755 GIT binary patch delta 299 zcmV+`0o4AY1J?o}iBL{Q4GJ0x0000DNk~Le0000G0000G2nGNE03Y-JVUZy>e*o!8 zL_t(|+G5n6_9%yef#E3-uV)|wFadEj5U&H`dq4~_jFVIY_CeW-Ks*_Up8##KyP`cn8GS@L0kO#8E(e28j0pu@kxh z3|PE@3phayIS)0InFT6wgv8i0e}H-`5at41GLir&-88{mU_+#)UqHMVh`WLKCP;t< z8rn_-G=2o)xloNSkR@24nsKGR7f?-ep@v`pkOAIU#BV}1E`~ZACjc4Xio`z-#2rAq xiP(??8E^`SFGFoSPHI$u42Wi+000CS0Cp!Vw@0K|Od(tG8F&h6 z(0WqxGByKu192-5A0(%=VS%PGQK*;tfcPvWe*o%9 zL_t(|+G1S0c5My=1H)4wUe7=VU;^T5AYKQ=_kb8=7$>O)?1Qoufp{_yKLO%8AQmFl zfURg^AdQVsgC;`_#%sV1ApVO*juYyo+d#Y&h>dX>@D7Nt;jx4nh@*h`3=r=HVkdM1 z7_fK)7jS|aavo|ZGYeGW2#K+0e*pDXAj}22WF!Glx@m&Bz=lXozkql#5O)LdO^^T! zG_;)vX#5DobD2Tnu$KP5?5%6^VZwh&zCI y6R{x)GT;;tUxwOvoYbgb{Qv(y10?_;zyPvEFSFO0f=t^@d_X|rqn=W5Dvs=fOtC)TaxN!e82;U zk3q2qAp<``BZnAZ33V;V)luk@e~i#{2=iJRG);oS(11t_Ko02u;$^@z`3u=VTmY0d z<)CbJXas@8V$sw+1!8#?B!M(2h5-YpO9=r`8eR;<-9Q)qMK-V$h*d~Pa$kUW0m!>R zgPy_!S&+O%tYPnfcnT0t1hLWcGR#0?5-!LU-9S7S>N>0dW}q1{u?WP!P6*kG&%jeq zgVvLhm$4bR8;Dzh_#io@4GT1li9)^92gGM7DGxygJ_2GHXrNOJ82|tO&p=H85MTff WWkcyj*+)eH0000(^mK6yskoK&=l_3uW}}Ghd2>}K zbTt)CXJuuTb)S~*a*ZKGhGUUL0Aqmvg(``5PTx)4jKU^L#TQIhBwSq3>d$O;z-JX( zo8!7hR*7#5I$kiem8#mcI+R{@SjC#g%s*vcr>m}y50lL0?Ca}TZx--&d~LWP+Ob`M z^=Z7qH^xVI9cnm5)D@)poRrn&U#yXJxW)CvMPpl2*Hh=KGAuV4yzT23cFk(|A%2C; zOko}KBd!%|9TlV!=JT^O=PpbP0l+XkK D?oods literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..761d1603e97bc52eafdd06a90b68aadd0ef56c5a GIT binary patch literal 356 zcmV-q0h|7bP)c{F00004XF*Lt006JZ zHwB960000PbVXQnQ*UN;cVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBUy_DMuRRCwBA z{Qv(y12WK>@x~HJMM1gCu4RZEN0w(q)&Nu-2&C3Apn@Qvru8rm6Pjcf114xh=Adg( z!JkVPX>CnAV*B8Wh#nfLITR zU4eKDQc(T{Vjm#h4aAo~7J+Oy2#uV4U=r8?q^*Fs1B$JnV);-t2SGN#($8P0q9&lC zUr=|m0jWA5u7KJa1WtTFiJ3r78q^se#rL3WB_L*lvS$GeN{6RbpeB2$X-;UK-Uqey zAV%_rYGemeKcHL=pu(Rx^8=D5upm$|Bf1aXA5lGa#6d~os)2=x!6h4AMivQ%MNh>!m%TVx57fxu>FVdQ&MBb@0FuBi A-v9sr literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..4ef1f6a726113e279f99b48d0190c7dc38900514 GIT binary patch literal 157 zcmeAS@N?(olHy`uVBq!ia0vp^JV4CH!3HFy_x^nYq*&4&eH|GX)}JtE?Rp91OP07s zlmzFem6RtIr7}3ClseUmAGnPVPbH}MwgLAg5gFNpLp4#dv}0Z89ZJ6T-G@yGywn* C?=T1e literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..81282874391d538b7ef564f866238224b514c97a GIT binary patch literal 157 zcmeAS@N?(olHy`uVBq!ia0vp^JV4CH!3HFy_x^nYq*&4&eH|GX)}JtE?Rp91OP07s zlmzFem6RtIr7}3ClseUmAGnPVPbH}MwgLAg5g;cpSW1s2X>%V22WQ%mvv4FO#sy- BEzbY| literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..b6fbdfd5baa775f32a5b1a1767c80dcaf31dc43c GIT binary patch literal 157 zcmeAS@N?(olHy`uVBq!ia0vp^JV4CH!3HFy_x^nYq*&4&eH|GX)}JtE?Rp91OP07s zlmzFem6RtIr7}3CBEfI7VI6a|Ns9# z@4%Cml#t-T_UQJ!&vQOC&Y0QAkkEALkAn?khd!g}P2t6iY+D+BFa%uAQkZslS)<^K zfB!9be)An!>u_hgZRY**7&8TCKZQKTN2?ufGj(oclzqeSC`L_5w0TYmOUL|80t+it z1*S9p{m60T;PQt?CpaBi**~&sbJVbCvLrc|9KDe4&N=WcvdvrUhH~e$sjG2uL2~C&&IM^_D=rfw$6kg28wx!_*L%`)Mg=xxe%sed& zA9)un%Tjoz;>OI;AhM0&W9Wiq4l@*#4O;#g3$T|l6zU02?Ap)#QBa}olvB&2sSYt^ zYvX5KaWCj~Q?@Sd}6kq$AOAwT%0Z#CdO-e|$S;scYTJY%!z hv>Pq#hZq>y7p>mJbY44$rjF6*2UngDGcXD$E$ literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..e49d95d949764537aade8ccf87829e876e153439 GIT binary patch literal 368 zcmV-$0gwKPP)h9u34?t=eNj12zZ@y34?1Aw6l68Ma) z;vdiNH4H5O)&cRFf4o38W^7=jgQq~u2j?;W{{eLN0vs-Qf-Mjqpt}MGcnieOF$@5D z1LWtEPzAWa3m`rX^)hBkL`qbOKuQvtaQ;F4{1~Y5DY{z50nd#90R{l+i&bzNS_m)z O0000p;?-djhV2 zB47<7$N<|!6?YwVM)6U1afm2x*FbcP@X)LE2n?d}(xBo1Nfj;LyB_%jt0KxOp-fwe zEA{9ukVWs&5Q)yq_^f#z=)gqx?n*=7LgA(pe?%A`>zw$D5%x;j>a?do8ln;b3&X?i z--naSJq0qT(zZ4UgI>HGp0El~;jHsfvk)RM)uekj{A0YqIWK^q_;W*e3$pXQ1W-#^ zbT5@};syF$k}8Is0&VIugwqtlQjnklVG4Sk-r)hxn;paLuEnqe7|EHAnX{zEZR@B;0{4gRCJ02r$Ofv)%r zWb(n4h%u}I+6ar&YQam;0J0dAJ=HO!rotaVB c`A2{O07t`|31kcPod5s;07*qoM6N<$f@E{!&j0`b literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..2d08c58f65c0365db02ef2e2fa99242d6179bd98 GIT binary patch literal 223 zcmeAS@N?(olHy`uVBq!ia0vp^93afW1|*O0@9PFqEa{HEjtmUzPnffIy#(?lOI#yL zg7ec#$`gxH85~pclTsBta}(23gHjVyDhp4h+5i<5db&75}sFeszUpWxJsp5$4|+CgV_q#l9`0|MyNPCh;&3daP5&SV76Cd zV`5m6ATRgxt^#YM!ymzJl@k+>`Z%n=!*0aWSRowpK~rEoODE&gI0hC8hB_AMuMe7< R%z&0Nc)I$ztaD0e0s#9(NFV?J literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..12fae28d7b07f620e25b98f1393db253be83b552 GIT binary patch literal 261 zcmeAS@N?(olHy`uVBq!ia0vp^>_E)T!3HEZPnf;}NU@|l`Z_W&tUqDS+Vv91mn?CO zC<)F_D=AMbN@Z|N$xljE@XSq2PYp^gTe~ HDWM4fAkSF# literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..4385e07b484dd4729b68d51e0a82561bdd60c7c3 GIT binary patch literal 223 zcmeAS@N?(olHy`uVBq!ia0vp^VnD3O!3HGno{rW7QY`6?zK#qG>ra@ocD)4hB}-f* zN`mv#O3D+9QW+dm@{>{(JaZG%Q-e|yQz{EjrrH1%6?(cjhE&{obIp+JfB^?<0B_-m zE7@QEnZLer&}o&c*YmLUL*hOLhnrJzwX%L88WrspOKAWrIv6) T`V2!8pydpnu6{1-oD!M^5@ delta 481 zcmV<70UrLf0*nM9iBL{Q4GJ0x0000DNk~Le0000R0000R2nGNE0FBi2Rgob#e*vCJ zL_t(|+O(FzM+8wE$KP&G#Ii&z5fNRAWzwIq|3P$$=u~2FX^E)qQldyH#h&)M*G|i5 zPMfr%)ghKhhlq&2kMHD}#(4AQ&5w_L>>Ho??eF({`wHHEuO@^jfg52FcN=rYdyBvW z*WeK>i5x@8e6DA~C8f(?Bu|;pf28MmNR{jj3}U{Uq4Wu?fKeAR6+yzDX>h_!Gf6|4 zZ?HF%K7&;osYzzhm;}d^t}Qh0$4nnAV9o^R?8CAdhF}MrVdlO}GW!I5%TiRpA$UQS z>q(gwwY8tI*(N|!la`WXE%5DNoOEejmxeV9Lv`3Z*He5@)v>BIM}=$8e^CAo4!}`V zW?Qow*L99aT(o2)t4(H9<_QuvYvUD1J zUACA}GN9xFlGv`6+6iB_l=LaNg5)P@V<@XyNFLNN1%dH(LR$QUJ!X>n&LUGZN5BKO zZCg|mSr;@wCu^I^gyy&fH(UI45;7*M4m0VxzFkS};BB)efygP8Y){QdhCff^_!VFP Xdgf)3Z@7=G00000NkvXXu0mjf(3RR- 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 d76dca75f2e31ec7f118376ec9e88742c55bfc3b..c183f5f92bafe70105965b3c482929d77d223b95 100755 GIT binary patch delta 336 zcmV-W0k8g(1pNXbiBL{Q4GJ0x0000DNk~Le0000L0000L2nGNE0I3(HmXRSie-BAS zK~#9!VqCj+Z5jgugE0`d0`VgT5>`S z*g!1Q@TEYkONmRdfhZup1TuWxf4X%ThBE@wDUAIVh=s_E@by4k4@|R{(G6V)#BmfR zQIO$zObj#tEJ$o03S9{IKFm-FGQ)Ej5O=@~LwBheIfeo8Wo!is%ur(@4O#}tqG*OKfO_*jxk<_Z%Kim4tb<&`kPQVTCZ$>ARwvj1 iLDvMjMgM0AQ}=+D^0+@n)Or-;3!6p^}=C{jw%VP>y;?X(PY zitLJ3hlogrh$Z?ye#6f+#+&!v{P@_%yz$xJ{C>YTQwf5gErh6nJ7EyM?`!X^0uS7R z0az9#hLT0JUI5o5T>%qi$^?^Mf0iLtvJWuIxHeDHXRrz;UC30#IeX^78D(lEO=OYA z-bDHW)=Z>2nWbX}oRV}s48tki8!MPIL38$H*bMJr4_sj8esnVX21CPAG{G@=MV1?R znO504vTU|#aLA;!JlQ=MI~XS}?Qm&Qvm{i9Ez)|HZd7$_vF2#f+S8POe}W@$B2yQ} ztTW>RHEYwlLnFeY0d`dqGL_XPWmKmVBx}|h1s`i>X4~}7T!lIY_rW1Id#*rXbM%oR9{O@R2ep{LLZ@ zG)GJaZr8M^I*+`a$+ 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 0000000000000000000000000000000000000000..2b9dec25860b8ffe5609cf476f29216f593c90da GIT binary patch literal 431 zcmV;g0Z{&lP)Z3Cbv;vD} z2B=sCx*#?Kk{NJ=WMT}E!()IPF$OT>F@TvE14sg+1~4$N08<_~DFRa%BPkkT`l#ZC zzesri1YYA&{~D^66UzS%GT<7NqXnfm;V}Rvrw*lWf($qU<%B@#N+d&(!8NEH2n0gu zBOn9TKsot9r%3|?6XZ-2Ag%}EeNYTyn}Fm%YCvkCde$?pUAq>Ys4jv9Dwhew63`OpJWyc=)V~*?@&-Wc2Q3dk0eBFqhXLjS5MTx3SwNgX zAm$bTaT?I}-{6FVBmojg1ma~-+iajVGeBJe3hYfljk{4&A{HBVLoo=z3QWVno0$Lt Z3;U29 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..e1b29c5bc539707206f8a8160c95eb4eadec222e GIT binary patch literal 402 zcmV;D0d4+?P)%oDtPR9Zp-wDC zD-XIsP6lFWAifI3{6OpsiiLeZyb_4Rfp`}X2Z5Xh#7$US0do2}sAiC!eXv-_gxUfM zhx0&O2gC+Q8V#Ug=b>s2LiI2(A{A+@Ks*bG69~lI0w7KU;@{{++HYu)wG4>;fY=7f w6&Ij^4T^=`gv!L-NQz*o)Nt@-CV&6~02%u^rh(d@K>z>%07*qoM6N<$f_^@iF#rGn literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..35570d84a2578cb1760c8d425b09eedb536e9167 GIT binary patch literal 163 zcmeAS@N?(olHy`uVBq!ia0vp^0zfRp!3HFQtmCqP6id3JuOkD)`V;1?T`z%r$r9Iy zlHmNblJdl&R0hYC{G?O`&)mfH)S%SFl*+=BsWw1Grk*a2Ar-fh{`~)M&#c#(b1RB8L>FVdQ I&MBb@0Q5^U4gdfE literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..557cac120af92a12387d0c8731b194b9abb79f7a GIT binary patch literal 163 zcmeAS@N?(olHy`uVBq!ia0vp^0zfRp!3HFQtmCqP6id3JuOkD)`V;1?T`z%r$r9Iy zlHmNblJdl&R0hYC{G?O`&)mfH)S%SFl*+=BsWw1Grk*a2Ar-fh{`~)M&#cPSnJF64{+_r6G{njkkf}7^6Nv0}~I!r*C}nuO$~90UE&I>FVdQ I&MBb@00c)fPyhe` literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..50f4366db2c9f9ce5f8fa75559ae78f83a563dc3 GIT binary patch literal 163 zcmeAS@N?(olHy`uVBq!ia0vp^0zfRp!3HFQtmCqP6id3JuOkD)`V;1?T`z%r$r9Iy zlHmNblJdl&R0hYC{G?O`&)mfH)S%SFl*+=BsWw1Grk*a2Ar-fh{`~)M&#c literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..50305fead6113e48cc090ccf9af1aa514a813533 GIT binary patch literal 163 zcmeAS@N?(olHy`uVBq!ia0vp^0zfRp!3HFQtmCqP6id3JuOkD)`V;1?T`z%r$r9Iy zlHmNblJdl&R0hYC{G?O`&)mfH)S%SFl*+=BsWw1Grk*a2Ar-fh{`~)M&#c}1^~8%Cwl_8|Wb24G zn7}xr!9ublpSjRfpm##s5jo|kzr0az>{?%XvIPm zX$I!NfPB+OT=Hs4F`Sno+O=zDcyQ>id3e~x?TT`HzlJ4S!vST5dt67>M|xcO!P;Tn zu!Fy2e>01RVS?T^75^Sa_Qo9y9r_cbddnLuI67ntGLNMma97Y{OUhM<^FL8}BJKzG zk}1eVOsvqP?+kAzMeh z!34$`4Hl9e`OJl;0>zV(88|*L6mkpPXLzJh#M8iNsSw9?M7{Awj|_9d0iLWAK`R!j zNHZ`82IQMQ;*wWWis8Hz(XL%H!-GSA&BMbkZda7s`!y`t8V)Ec+~Yd3KGNgL57rLr zh8_GJ`uf{#+zyY2cj9b4-t^CMobU-+ZA(BDi0E1PbYLG~Sz%-zb7(8A5T-G@yGywo% CuV`ri literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..9d5a7c907ac44df874f508681f33a4ade4cc0b47 GIT binary patch literal 309 zcmeAS@N?(olHy`uVBq!ia0vp^0zfRp!3HFQtmCqP6id3JuOkD)`V;1?T`z%r$r9Iy zlHmNblJdl&R0hYC{G?O`&)mfH)S%SFl*+=BsWw1G$30yfLn>}1mCX57!pF?)%qy@z zL4nzTvCv51KHH-#g=Z?q83Z0MJ`z*d$9N?0i39_4k;5L54u7VNl9p@-8YHhwSQ_B$ zX~w{|Xu-X#BcgUbE<1#lY~&07VK7l3F5+-|XU__EKKZ~R9)?DDhdrVl@tY^C_{c3# z&QK^XP|waeA?ZL&j^{iHWph1g#rTB4=(kbZs>Q2;W={4Vb8n?pC|17 zAl{Mg`1fbujfO_a4a`}uO@kf_r!=TvVc5jr(7?#>aEt15?_7CM05N#F`njxgN@xNA D^ss3i literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..52ce63376f7621f679a6bc9bf11c31f85e03e383 GIT binary patch literal 308 zcmeAS@N?(olHy`uVBq!ia0vp^0zfRp!3HFQtmCqP6id3JuOkD)`V;1?T`z%r$r9Iy zlHmNblJdl&R0hYC{G?O`&)mfH)S%SFl*+=BsWw1G$2?seLn>}1UCG&D)ZW;*kgX%$ zU;^We1`ElKeC9$^f#ONY3>+UA3b_UDGd$8L;%Q*CREXm`qTYC;M}|4!08iG5pcM;M zq#2k41M*EDamlMG#c*DVXxFZp;lZK5=HX!%w=2r+{Th~R4F{AJ?r|MiAL()B2Wy9Q z!w&wA{mm>Mh6#GxRQ!7w*&BB-bm&iz>Md`u;OLMo$UK&Mz+FL)Eh$$a&i_Q^iMSu! zM>a3`SL2>@-~i7J#;sqaR(|9(Iv||I5Xqo$fZ^Ca)s>8L*-1bjF?hQAxvXG7HQA(|{v>wSZ^f?r`VkQD=jy zascB~SXO|d!O0ik5=36#1TbE~QcV%U5I6cc@X)P6x1c4!2L8S}VDd+R zWzz|GLdS+EnlhX$>8fa6sT$D&{j}Hd6f?JdLM#?2cFq9}6~VZ|xN9}?`-COsN@!r+ z#-(77iAJ$qAeg1jmRv8G#Oo~rgUDFJFY67}4x z;kJ(nCG{UdQcJ$c#n&a7cV)RpCC9wD)Y?T@Heftvqe!wm{zQxrB|%L}@J-^gVt8aI zQy!kWvJViZ2P|(x^Z_4!AEt4Ap~{6pn!vSj7Qq94g7d%0>cjXMbi*{`n)k$#=uB-` zfGe4CEkPI2B$kS}aQL*0#D((&+{5tuKo`#crQeY+0R{kT!HiRYuJLUE0000K|xPmyol$DSZ{)e zMGHkwg*K8_FCJ2*Md`t6i%FZNo81||+02$D+59^2!OZTw?|bjfn>TcL;wbr_@&4-P zn*V7Xfga#2FbKqfcKLk`muXtZ@;zKpYyXx=&?uau#>9Cl`lZfspev(5R?H zm7MV$mD1~0&fm}?4t7N3z9I^ZEunnHbij+CL*CFWug)uOU0zFiZ)(>mVsn&1 zALmY)P6B_>xZ-q6+u!Ovpc}?Xh;(C`Mn6jX1;iD1a|(fxYG+ZCyrAwym%SpFZ-aV~ zXmktkV4srJZ&FL`YKlCsk761Drr`bSAOSJ%0Lz5a7|rSTXwFE~CC47L>@k@dk@x%c z9voA?X2Yc&{2MM$8f_$lHn0wH9j&4h1<{WKJptk#X*VUv;l0)9n=GEo%fO*JK`h93 z`Bf{Az8FLD(H9M|TVBlHl6V%xvo)WJ2F~zWhrx1O z1d7nH0g5KiAtzl`wBX2cP99~0r#AJp&(4NLa~?d~984IuG-On+WEazg=)Eo%nAsuo zfkAu9m?A>UcGP)yA(nrQOBBN*-?l6fjMzA6+q=bZQqQU%8XZu>EnUxl#g{!aYaP3) z(KoXME|OJO<_!f{C+FLcyctF6L$W#lqDP3;LDlHsyOjc&l}b#Rs`S*XeL$LSSY8I` z12z2K;>Pufl?%7LgY(!~#0gXcN8M!gVEmB1%_QSm^~93yOlMlanaQ}*L5HJhmZH9J t)U<5r3+E18WB9eN3+MmR|B){N1^~IqczM6>HpTz|002ovPDHLkV1fZN;!6Mk literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..946cf59d7efe46f6986c129d26ebfd08608a12a5 GIT binary patch literal 845 zcmV-T1G4;yP)wMO{AQUAOS0Mg_}~lkHZ$Kh^X9!b-0@dg@;|mQ z8Tb63Ya@^VE(4=L3Xs|NeP9Jx2Ie55bSuCE_kkN79AXFf0+E-U3LFET0Ve^I_wh@< zfbT~j99R=Xp-d;JWi?VO){%jxTcOc&J+I~4- zJ_WH!(==mne*yO(vhNIqZ6e!wgctbb$l=KIcI4DT(a@SaAV0;1HsKBf4;y1`+YAj0 z-Ff&>c$O15t#7Rr1Myp8TA?Ilo2-)|G6k8Y0z)cqYE>)3BlZcxtU}9no;O(zA+*V< znW&K*xzgeU1vWfr3#j%zwQeZQJHnxeCO{R}gMH$TzHS zE@r4klnt}aUDL)jRxMPMQe0YTS`{Qk#QZkdv(iro`FFSYQ$zbmIymbBv@4F`a?p;mV7a%f-VFvvu;}oDJZp9Q~nre9$ z9)^ZDpjOmd%>C@vi)f=;H4Ss9xLcf76*bxoIlAgyq^|^b9=reOCP3{0umzE1DOY+_ z%9hgY$mtvYj)L|z;nM*JQ*}I`rzat?$=elU#n=txX|+;POx?J zlpMRSb^0dL=kg|Sy3HY0*}MFqmq(x4ID7PILmXs}zWT z6pl`wHf>u2XMdBZ!yKMR#t#DvWIAjOMHXr^M15s-71U!baQz|Dz_5ABln|x~aZE?l z8*ebjGM-V1V`FL%6!B|W!@QeQV+WguE5k-rfqeF?M+XC3JQTew9tNH0(0ym%B)fz| mdY)x*8i&An#*K_jJPb^RF+W<>H4X#a!{F)a=d#Wzp$PzI229rg literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..01b2766d253318010163b0025a3d945b8fd4d321 GIT binary patch literal 285 zcmeAS@N?(olHy`uVBq!ia0vp^azL!h!3HFE-n+dJNU@|l`Z_W&tUqDS+Vv91mn?CO zC<)F_D=AMbN@Z|N$xljE@XSq2PYp^p8dXBY-3Z(le5e$XZ*@ze!o8T`sh)+KLYM0Y4=`U-Fh_N=J08Til43R(-RIh zv2u&)L~MXEe()#sHN9e3zw0aObjAWsi(|erHL1qc%PyxZOLk4Zxi&>c^W2O#OCvX* c>1SYOc&MsVzNv2$AJFLxp00i_>zopr0RMAzB>(^b literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/ic_send.png b/TMessagesProj/src/main/res/drawable-xhdpi/ic_send.png index 73e990f38b943786bed94a91ee1e10a0946fbe20..4c42bc008ef627b4eab3fa8493047310b170f30c 100755 GIT binary patch delta 706 zcmV;z0zLiA2J8hPiBL{Q4GJ0x0000DNk~Le0000g0000g2nGNE0L8<}Tah6+e|||s zK~#9!%$djQVk0s26$8M?0wykP=3r5slbuUIE}3cy^Ve|ua7m4PQw zni)9jDrgY!Rv6$mYV*`|^F(g9l*ix6d*oGW_in<>=nJZpEpabAPCg&pzTYAD>4LI0 z6X-d7;7fx29R#c{y{{ig+WiOzj;$QN>$6ZYxkuhdNL(}m)t!YrKKCM5a%>lHE-R&@ zp{T$j;zl?LS$=z@oxUqQe^fp3gOBlbBE*eld6I+&DKfuIn9UTY_J~$+KU`F zn(*5P$L1>gVWUAR zsLk0tBF_`xkp1H-ajk?Vl<=9(p^_52`8z~Rwqe;VZ`GHAizM*1p! z$cK@of*R{DQBjOZ7>ZB+O|=BTS{wl`BJOww+y>xdoT)+tv}`(hB^PY~s-StmHq#5< z0M*z-gmMM*DgRG6nepf7ye~LjrXIszhB1DJzhD$Zg+&2>S#1!CsqyEE8}M zQt=gr)zER*k}tqs9n%398F0cE*m1_c;lO37z!-)znVAT|?t>hE}KS5p%3Y6NhWL+cRYshR~ z*a76X&~4UL$Oi&OgTk;bf6`fq5)5oXHqNhn)&fW9Tv1mcTmGD-wO_zyt24Ce9LxI# zH&|~W_1417Ru)*Enq=FRNOOa#bR#NsV@%gO$Q=ZlhUKYg8VTbxGU6L_8FDG-HLsM^ z39Yi>>xmhPy9s1>Bbzh~0uBpOLZl2l( z>0mX(pt{R*ld{1Tc*hYNa?THeOms{XCmouWUW+p2q~P7$3VN-1?IQA#OA+S_hAMAtpV z649lU(qV}d5fRybKfaUancaP}^XAR;<*S|9H{&z!{oe2Qn=Mf+7TX=iIU}Ew56EAR zMdkB(t#L{64|$lpNq#0zlT%L2f8>H*H6fR`}i)<7#QT%SfLgbv*5jH*gW zz-wUu%b=GA?w3OTb%DFW0DU1>4c%7;-Y@~2RE{f#SFD3P1z;}G-Ejq#e}N}ani)6~ zS5PnDZ9l*XYV*`|^G0s7l*hlxN90v%_n!RB=m)BlEpabALB1`OO1tD>?kwc+xd*wDW4j;cGEzDk2ns9$ zZiFkJ<+oef>HE?{)e}GXe>h(!eB4-87U7_#o~*~%Or1oZ)qFV42FG5YJ;-q*5x;$K zY_2jS#p#b1=m~i!LckkrqJn%ZGPB0ImO*q!FlGk)8l}gq#=~2~?3Wylob6 k96KdywVLxE^eeys6x1o0OBDoA%K!iX07*qoM6N<$f@!rvApigX delta 800 zcmV+*1K<4U1B%W5y}rPXSw zMtj)prKRNFXmmAFjYKPzP)b=sC`;(?$8Y#`yxES$<;VB3NhUt?d;8|Sw>!~p zw-rde@+Sf~vImkE2e?DXh5~x#9CF)X0xeqyj-0>ZVus@I=?6n!lDgl=v z6<=XkUCqxBxZ*1?hHVb`oeBf4_yQc%F&%K30cU)Hon-tQ4qTNAjA1x4?u_`i0nMHV zG@FJJVZ+{M!+=Zl925iOul*fz){Dw8e{kOgki+_f zGhI^*_!u&48-}$};QvD4Ey#BQ&e?=*S-6=T__QdX&5k8&5^|G(&mjv%!f=&;WO)KZ z;0@Xn8UrR_CkCEp;{tafuf_$IG_P$c_jR2CtEOOGC8rR$4S78(P-@4Lb&Y@>$YNgD zA>_BvZPr!D7XsEsg<)N!f3pxJ82B0TuG8sgffIDDsH>1If6md`FJQCPJZ(Cs^1i_h z)(1!JWXSP8) zSluwF;qu(1Y;eVKcFcyH^MfE09TNpg!UA^QFbe1qqy_0oJsPOdawchA zts)|#5v^iOzmxOy9Pi`4j}~zcKX=}}=i~R@z30xo$7r|P2|p>9%l5}CumofPllxjg z4cG@RrF|}!bM@VkP?t{N5U4T<(>7*uUzK$_Rh_C5=mKtlIR)K0*6oUuz%h^x@U_xx z6P*C&e;Ca~BDj#va2#JCp9nAcI0$4T5Xio;V1Y5eS%ZWx=0`CZGvu0-As( zpa~>#;%SQ$tnrrtWjs9vDg-_v_@omU1r|ht$5V*y< zrw%u)F`--Uz#G2sXSU0hgJb%f<=KCs)8AFam5a z@e=DpJ82-Rt*&lux=@88P5<5vBixRr{NJ5?~VD zXbK^#BXas^9lbgY8h&LuPRG1TxkYZXydRu+mFbKCb;2Q@<57mJf;D+tr=7KC->|$0 zBm=zBEyEJYJf%;?|B`^xB6L}l($Mf)Yb%707*qoM6N<$ Ef@*|3P5=M^ literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..62e655bea863759108835104e9d6fdda2e4bc01d GIT binary patch literal 666 zcmV;L0%iS)P)`-sgux2>JUYzK=5REG6JJ6b`*+0Df$ROcq)RVPLY=+2ol6V=%V1I zKgm9RS4L00=n%2)O}ZH~=u*tOFA<4WI!ufCkV28o&qY3vJ#B=j`iO zpbGHqAbw{YfUeLM6s}(#0K7?JcM+f^G|mdwB?kZ{N$eH^G?;yW*)Bm}Hj-nXyd-u5 z0ct{Hl9>a$HUO~Ck0f>t0qR0ylp!rrz}^^%d*oYWMjsX0>Il%L$85G76Br-oDyTUk zd6Rtd%)K1*YTG`#C<{B^2xx~1^axs_(crFUhT1>rT%chAwns6|R{k%$rUQy|N;yta4*q*&4&eH|GX)}JtE?Rp91OP07s zlmzFem6RtIr7}3Cyta4*q*&4&eH|GX)}JtE?Rp91OP07s zlmzFem6RtIr7}3Cyta4*q*&4&eH|GX)}JtE?Rp91OP07s zlmzFem6RtIr7}3CYuwA)dDZm47spBOb%%{FPsvp4leuvJU{7$_rt2TF{#X060`(&S2fhM1 dk*ouv2@JEl_?!)AW&406Jzf1=);T3K0RYn9JthDE literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..09e75bb8c2afa9f715fe35d72209464f15276a78 GIT binary patch literal 191 zcmeAS@N?(olHy`uVBq!ia0vp^3P7yF!3HE>yta4*q*&4&eH|GX)}JtE?Rp91OP07s zlmzFem6RtIr7}3C&T|iP~S$ug`EChU#z&Gd{C|d|f)<7L}LC!)zvIW|p3DOn-~&{^qPBo!71Y2h$Xf_VGT@P9ECeKZ&PI*1qb}gs4;A)DmHnbBAW3nh^tf`= z1te+i9c}I<>H?A+chfp|S9JkNneUf^mB1G`1`qznlH$N49{n!CQ2x{sxC5u)bNohV zfetw0RdpHqCoO^PNrQ)&fgx)g`IsN4z%4jumq$(<0#964FWRr;cd!q3W*vN1fgf-J zHo*P7(>F~Ce!&gv{2f>0L=|Z9sr%Z;a;fufh`}cb#9HTRN)V*ZQ3Zn4`9Fa^2X0w> ipzs2loO+Y|2`~UWPD$#OGRuMh0000Vw0~ree$pPqqE0DGj z@L2&B&12ymtA`1aY7Ce%yg@7dDY}7bA>H?1aP-cHr*e|LAk~CLJhbu>2 zK$79!(dJ&FE+8pzH?4DbRTq$y_%nXrq&Z5H>}Q4K20h5H{La(2}E#wG@FO7!5(- z6a<1((0}1SOM^Y_-E)5Uc<3AM_wG6OzRR22I{!Fw&Ygj=Ge`m)gFYx(3HYQz3p{|F zg@7bSi58{Q1tcYw#g}KvLck{pe1i@^*+M|F0-E3n!1U!LB>KrvIDx{6r?N! zd=^0synzas*A|d0g9dm31q%U57Tl4ng@B~M*=TTf)CC;-p~C*Cv0qdLBq^?xE?17a zfF#4cqr<&KT|koOZrbGTsxBZY^Zin^5*UJgaO;08C=NX4(eDI|OxV8j|nKIX?Ma0%+{^2mup;GWCsS^IVT3UYnzoT`km literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..164ff9e103fbc1e8c607c3cb0565648188a5150c GIT binary patch literal 493 zcmV8fF^hZ zc?$tao)S$;sS8L-EQ>Es%0j?r5%>ljfU<>vWEnKTGbmUHNY+6c+<=UQfMf^sz&S`; z2>2|38h8U0FsCgbSps#?0YwV|Nfz9btc8H2$l0iKcGLwN`=P@AsIgyE1te*%lpa@( zx_~6Zy`#;&L|s5q;BMOB?y4>zDf9iZZ6)vl_Q9S1F|RoAh)2IOFqA*F1g^m$c>jGP zw7?Un@~XNF{gdv2jd6pAn1LZ{9Q&A`q`(z8W|zlK5&{ogRxjGG<5#c?Hm4nYT7fTc z0M@|mf2VJf5`2S8*7-B3#)&J?;!{W3$8xFjR*1pJ2_#zQNlFl;&T$2T)%h=hhy%AQ jK2Ugp9H-tSKLQK@?%PTN;+n#Z00000NkvXXu0mjfsMN}i literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..2a11310e6a6bda35d49508a843c9891c1c868b91 GIT binary patch literal 858 zcmV-g1Eu_lP)`6pHRCwC# zSvzkNK@h&ZJ3CI4_lrmf1tLfg&?JZ;AzJ8YC@3h>@jv(<5d|V89ij;}9iSA!!QmOi zBLoPLw|(bZz7cEb0NK8sTi?afjr7The7pC3J2ShpVEDxu>KbD@N1gf`x&j7S;}bJw>J4b_soCfLyILU_AT-bLqNA~4&*qO9Z`1XnvApY%r%C90!M(p z1>$&wXE+{kbp^D|O~0N1k2jlq7vY&z#>}3U02EQ4y2omn?5HkKkTeP)JoA7dV4ri4 z?Pv?=@|R^USg7;0FZ01X&I67IwmApcH=tizL~rH3wdWSG+uR5pWF-*4%RI=)HaP;m zs$$M!c%lg0Hk7BH>R@Px(Dz2Mm!N$>PD*V7YS7!1$rFdQIQIb>TuD*DCoJSPTYzeB zET=@C-d!}(RzYz$gO8&L3wVMBY}$5=TCgoye_DV^*=iK>kv$N);8SC(tHtC$g8VaM zeW8CuP?dVYGT#@inRb7a)7+)7qxSf?;e=g^8aA;6goN}fA#s{s^z!#W3FOPHE3ARv z$i`IrWmIERAhPSg8xY@#^L`Uet91pMYdF-7p?j=Qt4t;KmO2!_G^%aV5D<>znwZ2a k`<*xwkO^pW0lx(p0G=Zk>nRF?&j0`b07*qoM6N<$f-PEo4gdfE literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..e3ebd1b5e417967076f6afd7276708a7bce5417c GIT binary patch literal 1470 zcmV;v1ws0WP)1mLYmEXv%7OVzn8p8ep&aL+1adtKKRJYo1K~W zz4v?H@0jq-uXMAO+yq{J5r~y9!{P!jf6EWN|X}aS$&d4VF$ig*; zH}agZ7Jpl~ExMS?H!#UgDe(Nqfj4VKpjW@3jr3($#2u1N&WMaUQ@&oDj&$&>u?b`@ z%DXfSJPahmBybh*7&({BkcVZn^^T0X$*MMCI&wD87`HIV>83vh+z)(J?tY`==C$R1 zb2acNF_oljbOvN=?hr_1tG0gAJ&qL|<(9Cq8tZj$OuzS2;O}Y(Tns!(27g4xtf!XP zcSsGBG64d=az|{?@@@bZ0&f9s5CZFf0X0W@@V~pOvQJ>fPSngRMcrd~&p1}&QcYkL za3=6!5KsJ|c1Wtt$hbAYgtThyS+Tm45QG;<*Jf=_z6kUIo%-0uL!bAnGF6divA%@5 z9VA^!y4Uz2uxHW8A9=WcncA@V{!J~_pt(*dPSO0yzdy76QpZvIRdSKr^S{Vvq$S4E+aJggq&Vij=*J$ zSL8T0Qo8O0VzvsuJ@s2pl(Aqw(6ex(A-@i6z9-C1o)vc^Jm{WtLP92B&w~(y3I8b< zq+7`E;p8qLV;n8E0^P*L2T~p}9o>%DW_lmM-t(vyqo@ZCkLsQT{^Cx{8^Q zAo0CYfTO-=K4tbWTkI|(4koVMr&h=#92(^P&x#M6I_Y8rQe-BZ0=}la%5eFO z|G0uT6&zDWTU|!4%8{0F6X_ZBlM_EfG`N?~n7zwAevypsAoWvKy*}WFfZELaNszWfl>nD* z@YB(2^J=DhgVcqd1Ag@6mS-aOK$X_i-0szC+k&Q!`+&ni2&nc5Qx)iWMQFu-cnICI^v*;ch)^(urCg4Co+NVTf`%&IDR zHvn6hzb}?5Ap00N6m;NW5uinlX%N7X*gaQH%I#B z@rWVa1zhwviF?2_gzWet0OXl)A8^I8JAa0V*@_APdG_mvz@-Z9N!}mh5R$Pjz>t4p zHfSa72k-$Rvev>V$X~$Ykq_hx(X7|n3V=L|8~|E;4)JqXg-IImH z(;3t;2e|Kb1@2nT)>2Di5)&!`XviD(W)&QF?r2wl&om8HAmFN*Oz~l^)x+VS3(@=~ zWvLs#vIxGj6sKVX$R$N@^(O0YN(CfTWsL& z%}^5!A|Gg0;6Rhewt%>JsOvO}a5{q_Ulb*>dGs`-Ok_@gmfi=D3zB#|u7Z8a?mPy! z&PiQpyOi(wXe(~yOA0WJz6MO5IV^d(4{+n(0SZ{dL>{OGnDWL{K;(Js87pNKZ0Hmo zH+&ZGv7EAFxd*mMa!P=H*+RKBQ%PZqFZf*8YN{~#Rgj;sRu?)af={XaWWO$2FmZiU zQ`}{@dq7Tg+UACx)RfxQ-v=NhZiIL#dhy`Pz&yyGsES7xzLB+?@=Kc_C@|R#U=hR* zy^L?8XtiO$eI<*^F?^4Wm{~r}UpSql_??`uGgd5W*^diie6#R7aVQ`ZP~!s51Q-A@ WDgnbN@!%2w0000XChpGY=NxiA(B--Ry_f?gTHkXPm6Tleos}qX~HTuAI zU=Pp_NEYw?2N(fPvg3vlpn@L(Zgfa{A2T9<*V}}sz%K&Zu6h!pFfF>pb8gu^DT<;h z1*Mt%HC@wXEunR0^=v>-={o*3 zvT$-Sxk-y_J3;E!l1rn&D?r3a0`~&1bLR%0_8DKB?@N!*6RE{^)J1h;DwcZ4$Qr!U z&jT+2KRH3*KH#@_Uka=b40sjqm3nPTN=P{`x5{))jZJL?UbRc$ zCAJ|^vx(xz--F$2_1;-QU>X787&mnfGh<5xb^zV%I3oq553EL+T1HDp%UMLXQ`{5{ z-R)Kg9LXQJJgyPn8sG1Y&T-%qUr@8nTNkjeS^{?i8}boH=}=BJBS{kk!GOPg#!Wp@ zPTq0^9xH6qUia6~fZD7~(--nxgchc_seLOE2m)K#u_mvP$D5um%kJ;F)7>i(xTA2v zB~H2}ccR$@;C~ZbSlwEPj3&ukZ-IbEJa2o|%ZOl6a+qY1^a=PYq6P?(K@uWUmMboV zZowt|V(7-roQ&gU8ra6E&R*oXL=KQ8avWk)ZTgXQ28oWa93~&(+J0MQqf7jgJMA$u zA(6}P4XH(%wY<^-o=%E9WfB}bxb|F5JJz)@$DLkhMxd2T*kVvy#(G9(DtvLh7R_|)blV`1EGK6v0i8Q`{g*lq1~G(XkHCaLjJv^Svq>{m z#dm(TOh8{IPt1%!gtb2?1BKSH*0V5#%91B^l>zz5CzdTUlMQjFvz0coLbyV`y52H@ zb>u9{kU^8H8j;9R(qUZ#Akf8~{!xj*ME(Hf-4xJ2JK?~1kO~U^P2AMEN*ef~;5b?1 zrgS15YIX!tm(;#oWG@PztwccM7z(MS)Ll&tpN1jmDZQVY`m~yQ;2o}`)}K)`fo2g% zTuy8Ui7qZmep3wr>LmHjv7ES)*xwA{bL~h~+sjQ2TB(WO=0aFsd?DV~Xae#1_(86J zO1sx5tq`Eje7xWoN$ntQ0X9nb=xp@GL&5T$K<^ke-Ag+M2@qrgW zTm!@lfEN5kmS93tCZnbSXOU2I44KZNMBE6ho!waPzu=~EoW(2 zgaVO}97IOOAQmzNv5^!cLSjga^fd{PD>9QH{)_4ed2taBb;va6mB^QSla*V>8u_^1 z-0fAvh5EW7D~A?t!&zAP*IKtXA}l^fVk~vCMcB|?V`F2tpM~Y#BQi#LAxRkZ&CX(+ wDU!r6j%vwVi?KWMkWN~U9g)4CYd--70EJIjo*vsG^8f$<07*qoM6N<$f`iM6IsgCw literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..4e2da555cc3a88885090c2bca3543f1e47eff794 GIT binary patch literal 466 zcmeAS@N?(olHy`uVBq!ia0vp^Hb5N3!3HFs1e%%xDVB6cUq=Rp^(V|(yIunMk|nMY zCBgY=CFO}lsSJ)O`AMk?p1FzXsX?iUDV2pMQ-LNhrg*wIhE&{ob0?SYkOEIbV%G~+ zo3`)v)5HtpPfRkB6sza1o^7HdEG*BRvtP^5t$f*scPWCOT07oM@7*}PqxWL&YRizx zu9vgDChkorUN?)qBqKrp*UhC(-y7~u@IDp!UjD+t8<(X&&HA(~S>wWgzBo~<(Ea6^ zp*LRdjgESMejfkw61BUlSGm8QGHubJy~jg!FIDMyhCUUX=MewA|9_!Z|A#)s{aP`L ztNAY%?lRXs(7?#d#v@^nKoR4^|EA*d$@dPI{5ZCxl;K0x!dhl)eujCvTS6bMHNI%V zP!V)`;h}|xp1tzwYX5EW;pNJ`A$m7fulgi@BeeSa()f2vv!ib6=4xuySoEuu+g_Ph zp}ei*_V*1}h4rWJ`;*?5$&{h{^4XEVB=-4B7e0?}U}TW3%(&!P*{}o{DGZ*jelF{r G5}E*)bG~^1 literal 0 HcmV?d00001 diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/ic_send.png b/TMessagesProj/src/main/res/drawable-xxhdpi/ic_send.png index d55fade396f114a01e3c5f80d3ea8df613e1b0db..eec17c5470f1060b24eb730617bcd731959c66f9 100755 GIT binary patch delta 1014 zcmV>c zL_t(|+T>c_XBc4X#ZmwvzAGIo13!=nx6>fL>GB(z z@E-UrsU`^V9pFF3IYr5YyGay(Mg|N5n(!t`CS;`VEsxg-6TVZDOqFT1`-iZ!z;AOu(M-e@ur7HnhAGI2t@86IQQn{+jT6qcJL7yFK8yCCgK+LTv(T z`<3aQj+V!zZP$`z`8Z9Ij-eN<0jGkBH#P2unSg7CL$4;Nx;uYt=D z4kx3E7b~$P`d*?OP@uKCZ6;t&I2uL#Fw9YM#4dM*j?K_~9Z{C%fA2Ffn}C(7ZP|pN z;{5n1}oVFy^{F|>fZIr7=#H6r9h55n!Un?9e9_nF5bk{cYW zrI6ZE?agvHc9741ye~7!~u}Zu}qI*$0&RvpS zK0?u$y-(wcF&=TN{{gN8U&JX|B|fZpKPAEIWPlOiArEssisvmB>;=cr#b-5k`x6qq zO_|(CaLviCUn*ki_xFtyAEed$r6QW0S%IM94`{fmGYi3eX8I1bw3VWr;b$S+gRGg k&zbEv_haYI zY+JOty2?!DR~G(J-}5E`f3-kRe{=%!!_bJ;^o3n4K_4H2j6m)|zCx}-$_f4R|;u|e1P;BOn=1J9zRn8Im=;I8a8Ldw7}2WnDYkH8F2|R zC-^(X9OeL|${=PcmF4duW*g)kVOASNu`cb0c{7ffJmORU+dD&;w;(lfe?**ttOT^( zR+{l+fypB-LtX{EeH(LBXUxR9&(k68r-j3;(;YDt^8OHW8uCCV%t9mDb(Ap2Aq~1A z&eGUesA`71P#tqU;!23)q6p@sikJz9ucab95FvLjA0xvP%DY%wh{f6URSG2IYTOs%pp z@%;RREQntqpA|fLz?GsA!fcHiQKc^JhKXyLZwrCxg_vUM*G|I3)%G@nm|x*_p8*cD zxRBj>h3Qo`=6sNtUWiL{_M&4|a+r7xy(BC|-MX|JW?#OTeu%h=fAX8@UloLj_Zzim zi|L1mGuunZFBXr&JKuUa%+eqbe?m?{p2i50$NVIMX$fo)&t8r}wnMhC%=KgJ0%bJA z)za6tF}?0%EF;XzkZ#Cz=5Q;vCAhIaEOXbG=n79Q0hbZD{p1&q>SmU?o2-gHmmRYQ za?uIX3USBT-c3jFyqsD(e}JOG?0}qy+=l$MBs$v5-1&Msi+_|zE9VbT5VaL@ z4YCJYr=|Fqwa7B}n|s0UW5F*p1NHS)C3)J#F@k9|% zL-w*f*V`1t!)`0QdgX_BFeZR_W%CMTkma!S=ZBco9PcBwyqxev5c#JeI^yAkF~kD6 zj^u?{7x5F?FlvrkULbfPh)E6c2E*96?ufHAVGM`46Tj}PYRyo~8!p7oERVC43Ptg7 z!nj+=om!f7f8{iF+p#EiZYkcCBgOMWY)}C266BE#4C8dpfXE*0Ut5DV3nAJS~A^2M>?=5rP*5G-Ry^1r**514U z3tx(cGp{1r!Pfr!d;=)h5}!a$GV?ANIaQH)KbHLKp8x{@j79=*L4<8t00000NkvXX Hu0mjf8@)!K 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 3108f5bb34dfbeca0a2dc0236e87b28c2be0f2fe..633bad32f47d122772bb4473132621aa61abd0a8 100755 GIT binary patch delta 1044 zcmV+v1nc{r3cCm)iBL{Q4GJ0x0000DNk~Le0000#0000#2nGNE09RiS-;p6Ve*?`) zL_t(|+T>c_XIw!Pp6rfgDItUqmav3Y2utaI(5KSqQ~Q#qQ2JC#39Uv}S1WxKu% z8lv3jQ$wldX^HMjqmc-WKICbMmQqS=&uPC|)7!nfckj=cy&uQjy?gK6{k}7E&dixR z)M~Ya<2X}7h}&eFGcz;Wq7Tr$eVgDQd|zeo1V*0(pfIvWF01o@_Wvy~hp@=oZ z5jk#|Y&?wT%XD~6HZAM~SEFB&EqL_=Px26891{%z5%P$#6Bde4f5XDfANgJ&aV8Oc zi&}grVZP3&X!G|{$|9U;G2u8gc?i(&EnNC8Aa9p(u8i*m{I1sjV=;-aPF9sEctGDA zdGGTcHRMze;_b7`0iVz9%yM>+29MS0nCBUJ*+=)*$Fi&Yo z<6rh5%wzBa*(G5=e>lk1IPz1#`?D!4yAZ#I3QNgy(uW|uj=hOCx_N%ia^ibPYa3n{ z$Q}X5M(~QXN~E`XT`2nqZl4Ef13FB19Yv^~!+K&^swGik+ThhR6HAZd=?r)iBbnXuQtldX_FNt3h}`MAdW zDG0AX03#q{PIFC+=T#Bz1;=>F(|FHE*zHe1dJU1>Na&uABG|P{MZ)|2eIv<-@p`*d zgxQ%D2upq+YUyf2ScqJ}NY9Im8?=_bU@P&q=Mn7uM0(%#F`K$Q2fJ=B|MguTvx&Ud zrbOWSm`&u}+eO>(bX^QE6nW0eyl2Mc>c>R7Au@o_`|~yp O0000su#A~1RgkLsZa?4_sbxgZFHz#e+3 zUJ67@68d)$6onBeMbXhgBuSzu1wl~+K_ms2eINHNPPThH=l+|Soe#cNJ#Y8=-8VD4 zvvXB9H#f&j1PdGgC=?17Y`P#(e{?vX&;JnJ0X#R=fMCTe`g$kiEyz2Np8@6q)(E!{&}y68K#Q zbJAeCAi@aq9X1n!&&hC@{jgnQ5a**<<8u+S8}c0_Vy-iYVoll)^I94)e|f|gA?)uk zVP1#akVeEY$Z|;gJxC*dDljeX@?{n_uS4FygIUlS(^~L-DWc4as z-q#5;ZbT>c5avV3Hr)`%A!lPeekbH})iM7;gu$g8VZSJXIiez_pf9l+&3?lT4Q?U6a+3Uo9a+okXRj5SSs&OIaLpnX`lpXN} zlRL5;W|yhN;FyJ^F})CrOs#M*@%nt96o@dme1gpf1uq_Orsx)79!$CtRcg{+m^hdD zHV({ch()G;tS3yIZSOXS!2<95^mCY*IGb~s=@ky4;3G^;G)st*$pN4A%czgRi~SH4~3FdG6RLcjPEHU}U_ zQv}Ilz8Ar)6IrueC=`~!W;J9Zo4l>Ap#)6TxFG&e+Wxix&rZfAp2OAg0 zUW}z!CE^tSZph8D0J>Hp3@Uh)(kLO`8OX;nzO%OERrrjW?WoLsizVsEjA$LKGK(ZN zpjRd462?2l52^ZC(S_p!;sH8A( zri}xE5Qw5E22+9{2tz_32!fCVlG%6QJQ^PF+<>K%*=cDp8I|8p8M{3@7_rq z92{8xveksCoX_Xo4xa%!fd(MS$2NftU=mof3#QZQ!xiALo4_L$AlVQLcnrLYqS2}d ze9)C%2HsX6U*1Dhb{Rd`aM%J;Oujil-DVb%3PT_fbP%KAMkaqEZ#U=pc zYw__FXpCt5tOHFD@iVRv>Wh%P#lHGt=>c4Q3Yl*agpOM%okB0{=qESFg90HOW1tjATP^(cuZ5#rQlo7y(9r5nu!u0Y-okU<4Qe zM!^3npeCQsyS`gYr_+g}L{#EwLdXa>1OeL``TPhXU{@G4$Avl@8U?KT7YJ+W;mGSA=?VB!E^0S6ogW1G*HA-cpPo zKeo!gBPAk%iracc#3zaj{EsU2#+d|%zsBW9Iw90K~gu0)~C$dS!?JJ`oK-*|q zf#<-U58``VrxoNk73DIDTj*rDfCYt!Ufvg>BGV6?1xA4_McFMbLuLCxeov8oQk%UJ zdDLBSrV_(KVd};yUZGc63Frpufs6e89;2I&)${jKh18kan&P(IY}hRqngK=>6UhV| zS9=VRB46nd#;9VxagwJtCKQv`2(JE&{Uedf<(#wc7fasBMPYV3$gUEPRqmN+)_0ZII*nD0W)8kSCw>mU_QLPdRxhogM=Q6;3F{SVV(&BP37078U6W z*&xV|IS)ERsN7xwcRWl&58${EkoZ-6JX0i&w!KChu9K=tfF1KUJaG9AeBktATFPm7 zfYOc>B7Pk>>A`mn{=~4VB!KJ*@G!trTdC|>gC?WXib+YbryxI|e68Za$pFu|FMKpy z7l5qO?t}cxN`<`ifNivwXUNjK;mOX+vQm!a-0kbkY|iAd#4Kw`_7VLv??ylZ+?K9V^Fy4hv~K`Hh&X=j||(S zy`0ri$DMh#Xat0`MAUyl;eT~VP7_i5Yr}+)5nu%TwLbz305-7@tYU_CiU0rr07*qo IM6N<$f;ti2{{R30 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..c972af2bd7a41276360dbc43506fb5641a1fdf90 GIT binary patch literal 996 zcmV7~$9K@jm^AVsQp(2M3Eq)0EN zR4PQg7!(4cG*}D@g*?j`I2YRNW(Ln`1@JW9H zt+xr@`G(f1PQ2FuNeW~tK;0>-o9q=p0`v+r(uI!^@-Z4VKos;EG^C&l4iQ8&On@8o z22@#se1-ymPb{k;rDub@(I5aBMP0}1!DPY!NNXHe(_sKiYXq1M10bdmAQlEdR3kt% z41m5e17H9QfB`T72EYIq00UqE41fVJ00!WH1;7msZjWi8&th$vE@S}u1YlodJU@c~ z957`knCp8Q0d{@Haxf@7(P8F#RU<&vXDs^&P-hCqnd>Eu0Gw}b6L1Fswwc07p^;rp z-G>9 zIUxW%Mw0?P0v-AY{E+IT$cH67K&~4Xod8<`#C1#FmB(OifyO{jK@H*F2Hi78btLEn zwao>;^>@mAy3lZb>F>CF3pyjbYOfTGTc#05=Bf%Q+ike%{ZYvO=Roi6^?+@7p#WN7 z29gcXB_Y+hKd|k9-$jJl;({;O!Fx^So`8;+iWkYT?rqi$YRk)xC`NWRT4&yXZFrX9 zgQei4m50U2w{%`&!JWFjrqe5+r8fN=`{%sE;OEKbq;Ss?#n#b!;4WxYa26wHUqG{6 z1U^eXRxJ6L!79b%xu};$KpaS}2>0NO6;E4z1HGgvL0S0FBQ!<9z%PSNb^!T8nh`kD zC}$5qw*#!&zB<+#I2fH01|`lOT5S$jb#iVrOQYpu9}N!&2-a;kL3vec;yevx~x7_ zXO<)>B|Mnlw1BFR${kKkv;a7lm~Tk7wS+X<^B-G%Wd^_i7ytuc0J^e20t^5+%BGU? SoIwfz00001Gin) zU%09i+|B!+J-fktQ`@3M|HwO~8xQwx`|)>z=1)#}#hF1_YtPOr&M1>>*m}8c_KvUD zRi`JdvmUzxJI56W1C$o>I?0Ny9J-EODGltwCb)EvBS1pWj ko^$&}?6)!elldT)z%XZvPmdKI;Vst0LjHySO5S3 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..e86f91f938b403560e03e32e7a40691232397fa4 GIT binary patch literal 262 zcmeAS@N?(olHy`uVBq!ia0vp^20(1a!3HE7qorm6DVB6cUq=Rp^(V|(yIunMk|nMY zCBgY=CFO}lsSJ)O`AMk?p1FzXsX?iUDV2pMQ*D5XW_Y?dhE&{ob892-Ap-%{fSyai z8=N9kWU~z-JOkw4!Qkg8rrSw#<>(joH-lzJnW8Vg4+vZrZGAM8q>@6=&d2BL$ zWzopr0K!32od5s; literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..d18cf420d7fa06eea3c51d04607b4b7b67a4626e GIT binary patch literal 261 zcmeAS@N?(olHy`uVBq!ia0vp^20(1a!3HE7qorm6DVB6cUq=Rp^(V|(yIunMk|nMY zCBgY=CFO}lsSJ)O`AMk?p1FzXsX?iUDV2pMQ*D5XrhB?LhE&{ob4!u$kb?kgz_csM z1y{c)$+R;U&WUSzWyLZtWhJ}glsGHz z+3o&Jz5j9V@^gQd*2QE9K40P|@nGr|PUbz6tr8oqG6Ai@1vdCPOa>~PGYP0LJ?Odi gKW@f1vL6H!7z%3DJ=ujtEkPPRUHx3vIVCg!0I`5m`2YX_ literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..f7259a3144cf4037e5a53d356f25e6e6496d007d GIT binary patch literal 261 zcmeAS@N?(olHy`uVBq!ia0vp^20(1a!3HE7qorm6DVB6cUq=Rp^(V|(yIunMk|nMY zCBgY=CFO}lsSJ)O`AMk?p1FzXsX?iUDV2pMQ*D5XrhB?LhE&{ob892lAp;TC3vRot zzlfJy>=&`Wr1wo+W|w$Ux!{`*anUy7Myk^bI8IIp%Fg{Z$9eN-hBb4)-9Ga4Uqq2* zTjd<_cYo&`e|i1r-?vdp{tLWcwJ;uA;wO>d^{S#3XbDcRjWJ`gRboSOkUGx?uU9oo her#m@@VsF=12e-a6QOj!hM3hLt)8xaF6*2UngAftS#SUV literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..1c0924fdf5433568ac6229969470310eb5ce02ce GIT binary patch literal 644 zcmV-~0(#ZbAQ+(FxVem z*%0XjOrmZs8f+9$ZY~;Z78vQGfk9yCMFWe#-;0JD^ESvP&;z?54Zig+9Fl?S!JdN? z@HzMg27wyb2OYLms14SH4%0Gf>U>e2{?IrKb*sM$T1+axGkX{P?kFH*>H$* zBT$p4-nQxN?TlFGdf<09zV%FwSm#y_{=XTpuFl;ESXt+z2()G3HANOjUZBfTI*L)? eLJ{XzfB^sx6Kx}1bYblP0000@4oNu-Z_!3tZpl%DvC4_a0#A3id8^o5!AsA zh%*Y9tb-Of15ri+ohgt5Zy*aM*#t~xK?yvAG^2n?0^AD;Mgfzw%tlFOhfY9AKV+pp za?&qU0wz&esampf(FvHuW$&oVUP32el9JtA@9Hr|0TX?$>ViC&W)#qw0R`{^GK>Ny zbD#1G``oeCuC0Bm>ujJqIV? zbMOxg0yVG?I&7;@8>|T(re)OB`GP$Cp>Y`MoI&6g9D-M`{}{GFQyR3v_CD|dcEFOK z!G|#eU!Vw1K|hEO9H+n)I0ElMe&{#^9>Jdc3_PRk0sW-6!1AaDKdKq%ON|$$=0}>K z1@sr@$Fj0{{v!Y~;^ZrC$I5002ovPDHLkV1k_R20Z`( literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..d34c303719f77deaa3693966b3a60d46e359a6d3 GIT binary patch literal 644 zcmV-~0(ZUkL{JvpbB-FVCfore}UcCNe*a8hUXkFU-z&qFg z^MedNj2ZX@MQ{Xqeth6C1unoIc=Pi^haqqew)oTc1la@nNw0y0pavh*4D?vzMb>qk`=L%R1WAK9r=(EZWnBg%Xw0JF{Z%}5PcWpRC zc@e1cskdx8dpj=cTo3%l#gFKP)XP!ztm(*Xo#6nQ9WPz>M$M1z`$i7O);6IU$#2QE$AnUMGcT=@qKD_2HW%F=}< zK0`Euq5+Y&fHJ&hrqk;=nL|JW+IG&Jwv&Fzmxg58-hTHyZ*P%GDG_037?A{#K#@R^ zK#@R^K%s?M=moAkJr-&K26~1=WkCsGyreA115ki^U>&fU#!$7*SXO`*9hZUAz+a^* zPzA6N*g)b)2j^7LaW@^?fa}01;4E+ssKPGLE_$#gMxmRDtH2@PL>L7^H);hQ0md}l zqY~H!Yyo}%{s@aeXe}p;7;KZkZgRVKz;saSAdD*=z|%fuB8+dBfO~={P@HD5+2^c` zG4CSqK#*JvYnSs|vX0-tn0J<3Z^&1Hpo+$dm(|_@Mt|p;jlkMD;DRxW>&+4I2eq>*1}_UJ6GaOnE`tQLK5y)`! zEKajg4X{kxkd-v$YOF)pMm_<=>rm+;pr_u9!E$dUnc;37Ii&$i?z*JCVIBOq+AT-lUr7Cs&Y8 zvZ`Yl3AqyQ`-eE2uw|FA6u*sb$UH}m`pEwZ1OYn6-LV_X@#|pRjV@wTn@q*81yUgP z(Ic8 zR8_VQAKXFAdSfTEci^`cvp~z70xhujspYvTyC!{0#O;3gGqarwK(l%ee$&U?hauLS z3gooEnbp$GLrk%gnFmlCJ%sMP6OOg{X|rckr8USLb39GBBY_|etwK+>#NM=Sx={vP z?v*GWCLIsW#YM+OX&~dqBisly;k394IL6(SEsg~OH^X}9Tgb&hVO$lPZX3}r%>7WY zF(&dmW%URIR2y`m97N>E5eHQtti4KZbo3%8ue6x zcsU6~S`ZBT|B8e)novngp?Q}(Q`~vELo1_KAOddOo(ZTpm~F8-FQ|_zNFcBx z9K>sp{}Lxiz?$uaVE8g>Q$p8X>O$rhVSC}M| zKLo^m)k$WH!4hLccU7-DRw#12aS{l3cHsteFFW+Hrdc52rv>->I-dmkJG(5AJCp-) zOK}x(yZy`9b#HvoyF{_A=AN3Xd+SYmEr>*Lc5x;uCG?%mn#ZtY1q|$ z&Y5%0%#=@mrIG!gW&P|e8P6MRKn4KnPXL_&tu3VnS$*)#kDzUQ(ZF#R`oiu={hTel;-wzB9XM6FpE5J8L zK$qhAE1{E0&cx8D3-GZBTJPiXE@sGW(v;hoDSyZBaT#*{#P7YR$h*y9O!6w0~nz7m<9N_J_|G20mK$*iLG)_;(Popv)xx#I)@!_ zi+k}}9yjY*w>g13d^{7pq36zOA(I=6wmk@tzUwQ1j)p!0ZOj17et@!8hU1^ET(4&-RP5GIqNxTk#qQwZXWL2^ix|~PsaWKI- zFy64@vfBZY0Vb_1G=oloKIj3Cl(tv}*1T9OaC$wwCb13vZ5i0K%j1&U0MeX70#pfI z0v)9|7ll)O4Cd6_mw6M+ZojCDKZ*fiQwES`6bhh4ZZeq`yHL+Tca%o@Eferf&w<5n zd0g=TKx)(t(B;reRl_%^-E_o|Trwh#ioXkx-t=(X_mWT21yG&Ko^-RSPAu;kdP`IQ z(mD(p8$8M?_viwMz_Atfz5>kov(yV-A{<}s;kd5?i;l?`AgbG3s2IvWfN6cl%0Ud7 zl!KDb5aT^MKQDl8RrsAYQ5%1om66csh7d&Mw5QHkHDPK{fF`>PN)7i{rzVzV0a9)J zV{~qd;?&%r0HufLT<(NvZDr*sNRYv#H7X*2MGd(EG>jc8kET#ntYu{^h}C}baM)Mm z3eYu*9%#h_eq?1XG9=b{lt*#`DBbs1;uF>n1lj*q#fVk|Gn?oaAX`z!kgO{Cb$+zf(gz35}T@$fce@y0E4IHKZN5zhu2jwv8||bN%csPBs%u z%XHDBziA(JyR6Yhd*up%GoPvF&B82cEH?I6H1W7mul3;+$8o8OiN^ZzL1WVMU$I9k zI0+*RfSSOdhV0$Vr}0SWaWX^Aagi#IJT4nRR1_PUax9@cW9JcjKEN5BgDEx`o%U?a z&iZ%7(c`lLG*ngd(aj#P;j)~+=onX%&(h|H47Oi!ctkdU6a{aox4ztEQI1y;z@d-e zQTtSVJtgCcqt)2}QrUS@D}$u6rtOnOe3V8X)ExvMp}dt|ar)@Hsf;xJ+&>kdhytG~ ztuY8^e*_<%#a@j7g;Wk806}iBSz}MB-Yb#~pnVFY>oDqQTWE!p zr2|83?$NO&UWKs>UG0D`9I80nnhhYb!R@K{LRdaRtC`g#p2W-U&cUI6FKQF3H0OV+ zclymwB%PjCB>70K0D(owhZfL_`{?S8vL=29O$h2u$dvE&s~>>AO>3iLj443ExLeeB z-+;V`R*A%v{=gDT#o*Wi84`Mf)tEULu48!0;dUgdEq=23%?dh>D@ZmEpCamFFCe~o znMbY3T<~FTa=b?lN^H{Ub9zZ!+2Nc0mOFO3-n`}rM?D0|q#zA8WlYv4K9#IE z!jpz-9pjhEl+EKF8x^!Xll22ZE?5hT81I)sUH~;K%xsGGl0#nr6t$))ET;wjXJ;+| z(JIkIN<0+i5&NvNMu*}#$2ebc=2OqANQT?3Q`qhdok3&K*%PtPMn|ivlg|eM=qW{1 zJ=o~9FDgrPl14TBk7|PO9hg@~5P;fLEW(2>rX{%LhK~`kXEAl{`-zO-%W~i4ier`h zZ|g>|iIAG?47td2lO3ZszbWb0dUkCVBP~b>wWny zpO4$-0g?s!&I3rNmy}t>jj(YbbO&6)SjFjGULBqfKqPNKUsD{ndqC<4ol_FvbXlW# zB(wK)% z-U&9{RPcZju^8_RQKu{cNEdosMN`c40M1829uYLJqFKosq29X<1)mJ(eFiB1xvX?P z)LKgdW5CiW$PH&wtt!Kn6rS7%aDEN?sC*O8CYMQzp(?xQWOh_yfb-nLO!1YhaJ~(+ zLZ4!qZgUKL-DKQzLIzVhEN{87PF|CZI<|#38~Z8=BwDq8eg<g zxr3B0p>5Fy?EqMg_H^jFp^jb8NB;RaJG6C*d=qV-DpuA{1wPu3(V}Qm-!sU=H<8l% z<4d4t7vLF`g*QWAg6=I8@>UUgmbAw8Ph?iKNOW`%OJ;`(>l@jB{|TnxQmpc6#Ptt{ zcL~v+`w1>kw7*@I7LZ?~>1i6GcY4NM{RE&?`3w4CInQpy1oGRQvy Z3;?8)3)kRq7FGZN002ovPDHLkV1nzVWkdh~ literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..7a099f7cbc6b3b37f9fde3d8991ebc8dfd7f54c8 GIT binary patch literal 1290 zcmV+l1@-!gP)xa#EWr`qimBzPd%svMh?QJK~W9kwB3^kwB3^ zkwBqEVXl9m`&lZ~0`&J3hRT8}!J@pfAQxZ(>c9k8A!{h#VJ*MGlpL4A32-4_1u6v_ z!FmxVX5*T2IabTD9b5y)!6|SWw8AdXKDn`GMWI`SE8qY)8b*QGjoQGYV1c3EDB~Of zwt^qQnXm}N)^f_jU|R)V61RH?CWBfBaa`#H&-j#yIKEv0_Xkm+B6*4}K4)c)d6&Va zAh{UVE*G-0j^E&zcTQYyz*m7#MRQiUDA^@wXcM>pcDb@++c@yiHr%u|C1W-()R6`#OThWlFKnWwuwD2^?={l`}R#wZxyU_ErL}l~<<>*rb zzg#O>&C;|WT`W^0&Co4aPx~(7RYItnG>m?)f$l**%?At;;A^Nz-mf}h* zErE2$Hwx0PjNPFap<1&%RT5}JRiJ8m@5&NlG>dD$E3RZiOQ58xX_ufvE_P8Jm(r6Q z-Sc0ps0h^GQ)p3U{6w=8>Pt5n_TBOe!t-P0I%r9AyJJapX>3JxsHFME_fE$B=*RBj zT z9-(dQ!m(CL(@Cm9FxQPat{%88fe?pQ(335yH?4nHu}%qkP2OS5?ukySl>?Hy^~$cTt^noJEm?2MEYf$Bx9 zi6_k)Q7miE88T+ z{Q{3z^#6m*7mATUkw6h5fg*t-fg*tdi9Z4i03sp*7@m4q%>V!Z07*qoM6N<$g1rk{ AZ~y=R literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..8fb075f6f02e2a44448241afc99f5f22f5d2a99a GIT binary patch literal 2436 zcmV-~348X5P)^Q05ILxH@;DEeGmWK_G^!jEkLV-(^Ik{pOn4wX~nBtlw?Wu zhP?0N-|4GQQsZieuIWK7t99r(y%Xp&bYrp2wR?fzqdilqhGz8UuWW7SfFFaTH%ndf=p7!{2;w>V z&w;)YE;H`&d!B9TXnI+6Y)}*G{PgAYdMImEsnfW!LDHd02~t|`*<4BcJ`MZ=SZd`) zAZA~>qL?Ix9XUg=-&!hK_5h*2xS;6;%qb7DT23^8%!jHZ75b6T}m|9l*!P z)Z8P#+|=Im8#L$?;*0Kjp5ph!0+GP0h*v{!J)Sf9iPJsozr-kcqy$N8-6CjzNcg!ZupGCsN?9#KJi^^)DAt1BgFrKzB4hM2Rbu&`_d zL-P6}Ty2>6>cL70`dX2CWN8qtb%HgZ@d6o2+Di!mD(WqlpbmCrdbChI&$0$K#G+Fc z0sEeE3A&$9&j`}_|F8x(Z@{~sIDBWh1g#*d=YO(UV95AS5F=U`ZnnZHL0)2x$3VsW zuh~ElANDP3wOh#90w?N$d;J%c`jl&}&Y@GrSU*0y%`O^36g=wI?J(q@P;=_7cF*mY zAf)T3TxqEe1)s+-tLBH=kCujb5)o%H=4X$Avb~~j>yP-~Q4^}crcc@S!OfI28y9GH zF4jlHpR>ZrnPiLDFxw4szQw3@GlNAy)K+$u?PLi@ivf;}=W!M}(NZTdsE3IB=Y^7! z#KVu{!FAT_KxG3g%68=4P-HBUC8~~GY)25E6l*UymK9#HUxI3k50{pmxMDARk9}1z zK^KX`AGaf@oyb5ZgsUgV?kf9tD!VTqvjiDNvT@>YmmNV7YTidEL6`G2p1Tzb$_9bR`5)%QTYU@k^Vb-xdvKPOe`_P@Ir< zP$)eL!fnM9JM4m}W*EBRBMzs^CdgohSc2xUBNj@v2^tveTiM$JlT_-t;&ud$5ejNC zG(+5rRv~1_o(i&KANvbhD{Q4!*Y$Sd@Q58j+y_q=_FX2C=@P1-I-Po^vraPUqLZ|YwooWRTt#i{;rxT!lXDn_>myKIRwzNbK|RwMCj=cUA}Fi% z2(QIjprFNUBV6ZkM!&flM_&IZyADJ)F`>z-npE2i!{{tHJb^-W*hw{ioRH&vp_GUiN6rxMv7C(ms~(4ZO3!ygi481vJy^fiG}pFJAW$X?jomz4-b@Actqo zQ2c`ymHQ6+T-M(B+w^Y}<;S|jrNpXwCI<;&Fg2cf2(Cr#V&r={k|GGoUyMxIQ`rsh z?Pc{kq{pN2hb%V08~{1bIje@8*+~nMJdp3Eh# zff-8#M-%<2$<$_^uUVY3*=~DOwFGhFYw7={zQ9mAfYEI$0^`z}24i%})Wxa$vdQcw zc4c+gik!pcUc1u$Vths5cdW!-G5!utpe69MugN#&S|CO)26tMMO=rKHf7yXHzQoKo z){*Zwxw)Z^o84|hL-xq8_`<#yM9w8~#UNQ-h1zf(pQ|cyDo;;-2y)I?onS{$wS_0& zj?H~~D?s_Z#N94EnI1s!Jg<0_*S#U{u}a?1=Q&MgD$|2fXC%PhTkE$uyDN*yvOFlsQWUNjRs6~b5zit3-`LxQ5vd!v-swPQ665HN zT(=eU0ZIH#iSL1^H6~G|S3wXj@ZkM?kqPd?5JNloX-#%5Vs-I8rJpl|8ZL+Zi?kmV5HgWLxkG}}q?7}^G6@C!-6L7&T<~=p&S&pz7 zpZID5e@S#v1=r$BKzw5TF#G6#f^pqyHGLX4RNy*3wT`P%hP;_9yCYG zn%hjxFOLE*G{St++<(zEM^JSpAyuDap@jWUfB^u%Ivn7*IAxju0000wy literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..e95a6252bc555acda25fabd9e468d3b1f19f46b2 GIT binary patch literal 573 zcmV-D0>b@?P)s+`L@cq9SoV-5mF>_*qC`a5Lptm!x)iY_ibS2FOKC}~RYatS z=+duKL@Z0h64Cd`Gi;gNd1rQJ-oAXyVO~3*dFS1EpJ!?whx>(%G=T&Nfo9Oa$6N3P zZonlt0(qGqY}w0*T8VK1Fa?sJwal0hA3J$0HHm^NFm6Xe2Pa@!xEH#qZLr3Vx1t0MKIEzNA~RsgN`f9ikMK70V62=3 zt?EhPPqskEUkTl8nmkO9*T*l3B#Zc&2>)|_Bm%r(R3vFg#1zbek=RpWKqrYlp)RyG zq9hR(Y7^ER>dAA|csJN6AcWtJH?g+T^ zSYQ{dRI0XVUG#b=LIM*q&CeU?1{s$H7Qra(6|!w0?I(k5{Zj24k#B0jX+yjN+Q6Ix z8Tw2x1iGxY2ANL-MShQ@xnYTOm!|Xg3Y`V>d^`gO;8oW4TYv!o?>|#aN~LK(00000 LNkvXXu0mjfS0L`j literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..f60d77275b598b712b1d8a468ea19a4996b86d1c GIT binary patch literal 416 zcmV;R0bl-!P)M800004XF*Lt006JZ zHwB960000PbVXQnQ*UN;cVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBUzGD$>1RCwCF z*v$#TFcbjb+JgfK1vl_4F5t;6y!KjWZ~}X52XF%~o?O6_C!IhL9Ke$=;DZ>_wC}GE z9&OXY2T7a0WYRQECW*2v|E}A%ox`Dk_FMRDo+-u;y10b%l^Nzi3&yJR7?a>FflX~Q-OwHNeHs040t{kl)}`Z zF3bdqVP;T>nL<8h4k0!j148Tr`N&2H>_%52JtOxIkd-#(prtkFzl{jqt-$a*bKu$v zjLjfsVAtGe0;Xntb+GS$rV0-EQzt>Fh$~G@4Wv|8Vvt%lia<_9%m%r&J`0qrV#uI$ zeMSPsD^IA1`@pU0nmPeqAy4YN1rg9e8)$!=YHGG22x2~E%kaYF4^c+=!IMLJ#?A=VB@)o z&f8_~)ci>`tGk?g)@Ax;+g)yKwY*i`+wRIJ$Y0Rj|MD8!t~q-puU+Q(W%cFSZM$g) zw{5ig7uy!M_-!)hGE3RZbAo<-+q38Gi{qy6zu);<61e|S|Lgv9A^#cWeZO2h|F?48 zGMl?KRoQQ(Z0EcP@v8KFn|yqA_`5Z~p7%>PO@DCV!a5`4i+hV7vQ>7(Dm}P2JMrd6 zujiHB*{?e;%5PrYCs)=|eSK|m%e}qjGykO8eXqDLpUA=cgZY>00fy5N$6f3C+Qop0 OkHOQ`&t;ucLK6Vdj7Vqz literal 0 HcmV?d00001 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_header_layout.xml b/TMessagesProj/src/main/res/layout/chat_header_layout.xml index 72e313630..8fb0b2f79 100644 --- a/TMessagesProj/src/main/res/layout/chat_header_layout.xml +++ b/TMessagesProj/src/main/res/layout/chat_header_layout.xml @@ -8,7 +8,6 @@ \ No newline at end of file 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 d518b9400..6f7cc65f6 100644 --- a/TMessagesProj/src/main/res/layout/chat_layout.xml +++ b/TMessagesProj/src/main/res/layout/chat_layout.xml @@ -129,11 +129,10 @@ android:scaleType="centerInside" android:paddingLeft="4dp" android:id="@+id/chat_smile_button" - android:contentDescription="@string/Emoticons" 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/layout/settings_name_layout.xml b/TMessagesProj/src/main/res/layout/settings_name_layout.xml index 5badb9dba..332f30156 100644 --- a/TMessagesProj/src/main/res/layout/settings_name_layout.xml +++ b/TMessagesProj/src/main/res/layout/settings_name_layout.xml @@ -19,7 +19,6 @@ @@ -69,7 +68,6 @@ android:layout_width="48dp" android:layout_height="48dp" android:src="@drawable/ic_edit" - android:contentDescription="@string/EditName" android:layout_marginTop="4dp"/> \ No newline at end of file diff --git a/TMessagesProj/src/main/res/values-es/strings.xml b/TMessagesProj/src/main/res/values-es/strings.xml index 3ce933b22..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 @@ -348,15 +348,6 @@ Los mensajes de Telegram]]> están fuertemente]]>cifrados y se pueden autodestruir. Empieza a conversar - - Contacto no asignado - último mensaje - emoticonos - enviar mensaje - avatar - cambiar avatar - editar nombre - CACHE_TAG \ No newline at end of file diff --git a/TMessagesProj/src/main/res/values/strings.xml b/TMessagesProj/src/main/res/values/strings.xml index dcd991a20..3b850b794 100644 --- a/TMessagesProj/src/main/res/values/strings.xml +++ b/TMessagesProj/src/main/res/values/strings.xml @@ -348,15 +348,6 @@ Telegram]]> messages are heavily encrypted]]>and can self-destruct Start Messaging - - Contact unallocated - last message - emoticons - send message - avatar - change avatar - edit name - CACHE_TAG \ No newline at end of file