From d29eabd16359a4433c37216ea251a7f8fb3c398a Mon Sep 17 00:00:00 2001 From: DrKLO Date: Thu, 3 Jul 2014 02:39:05 +0400 Subject: [PATCH] Popup notifications (not finished), removed in-app notifications, DB performance optimisations (fixes for Android L), separate app logic from network logic (not finished) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Note: don’t upload to any markets, it’s may be unstable --- TMessagesProj/build.gradle | 11 +- .../config/debug/AndroidManifest.xml | 2 +- .../config/release/AndroidManifest.xml | 2 +- TMessagesProj/jni/audio.c | 18 +- TMessagesProj/jni/jni.c | 66 +- TMessagesProj/jni/sqlite_cursor.c | 21 +- TMessagesProj/jni/sqlite_statement.c | 12 +- .../libs/armeabi-v7a/libtmessages.so | Bin 844452 -> 844452 bytes TMessagesProj/libs/armeabi/libtmessages.so | Bin 795280 -> 795280 bytes TMessagesProj/libs/x86/libtmessages.so | Bin 1242164 -> 1242164 bytes TMessagesProj/src/main/AndroidManifest.xml | 27 +- .../org/telegram/SQLite/SQLiteCursor.java | 31 +- .../SQLite/SQLitePreparedStatement.java | 57 +- .../telegram/android/AndroidUtilities.java | 216 +++ .../AppStartReceiver.java | 3 +- .../AuthenticatorService.java | 2 +- .../ContactsController.java | 32 +- .../ContactsSyncAdapterService.java | 4 +- .../{messenger => android}/Emoji.java | 29 +- .../FastDateFormat.java | 2 +- .../GcmBroadcastReceiver.java | 5 +- .../LocaleController.java | 33 +- .../MediaController.java | 27 +- .../MessagesController.java | 1293 +++++++++-------- .../MessagesStorage.java | 378 ++--- .../{messenger => android}/NativeLoader.java | 4 +- .../NotificationsService.java | 3 +- .../ScreenReceiver.java | 10 +- .../{messenger => android}/SmsListener.java | 7 +- .../java/org/telegram/messenger/Action.java | 2 - .../telegram/messenger/BuffersStorage.java | 170 +-- .../telegram/messenger/ByteBufferDesc.java | 17 +- .../messenger/ConnectionsManager.java | 425 +++--- .../org/telegram/messenger/Datacenter.java | 21 +- .../messenger/ExportAuthorizationAction.java | 2 +- .../telegram/messenger/FileLoadOperation.java | 225 ++- .../org/telegram/messenger/FileLoader.java | 16 +- .../java/org/telegram/messenger/FileLog.java | 1 + .../messenger/FileUploadOperation.java | 13 +- .../telegram/messenger/HandshakeAction.java | 142 +- .../org/telegram/messenger/RPCRequest.java | 5 - .../org/telegram/messenger/TLClassStore.java | 12 + .../java/org/telegram/messenger/TLObject.java | 6 + .../java/org/telegram/messenger/TLRPC.java | 452 ++++-- .../org/telegram/messenger/TcpConnection.java | 61 +- .../org/telegram/messenger/UserConfig.java | 2 +- .../org/telegram/messenger/Utilities.java | 253 +--- .../org/telegram/objects/MessageObject.java | 29 +- .../ui/Adapters/ContactsActivityAdapter.java | 6 +- .../ContactsActivitySearchAdapter.java | 4 +- .../org/telegram/ui/ApplicationLoader.java | 17 +- .../org/telegram/ui/Cells/ChatAudioCell.java | 69 +- .../org/telegram/ui/Cells/ChatBaseCell.java | 89 +- .../org/telegram/ui/Cells/ChatMediaCell.java | 79 +- .../telegram/ui/Cells/ChatMessageCell.java | 36 +- .../org/telegram/ui/Cells/ChatOrUserCell.java | 63 +- .../org/telegram/ui/Cells/DialogCell.java | 143 +- .../java/org/telegram/ui/ChatActivity.java | 696 ++------- .../org/telegram/ui/ChatProfileActivity.java | 11 +- .../ui/ChatProfileChangeNameActivity.java | 10 +- .../org/telegram/ui/ContactAddActivity.java | 13 +- .../org/telegram/ui/ContactsActivity.java | 17 +- .../telegram/ui/CountrySelectActivity.java | 11 +- .../telegram/ui/DocumentSelectActivity.java | 2 +- .../org/telegram/ui/GroupCreateActivity.java | 11 +- .../telegram/ui/GroupCreateFinalActivity.java | 6 +- .../org/telegram/ui/IdenticonActivity.java | 8 +- .../java/org/telegram/ui/IntroActivity.java | 2 +- .../telegram/ui/LanguageSelectActivity.java | 7 +- .../java/org/telegram/ui/LaunchActivity.java | 69 +- .../org/telegram/ui/LocationActivity.java | 4 +- .../java/org/telegram/ui/LoginActivity.java | 7 +- .../telegram/ui/LoginActivityPhoneView.java | 9 +- .../ui/LoginActivityRegisterView.java | 10 +- .../org/telegram/ui/LoginActivitySmsView.java | 23 +- .../java/org/telegram/ui/MediaActivity.java | 14 +- .../org/telegram/ui/MessagesActivity.java | 11 +- .../org/telegram/ui/PhotoCropActivity.java | 10 +- .../org/telegram/ui/PhotoPickerActivity.java | 12 +- .../java/org/telegram/ui/PhotoViewer.java | 221 ++- .../ui/PopupNotificationActivity.java | 418 ++++++ .../ui/ProfileNotificationsActivity.java | 71 +- .../org/telegram/ui/SettingsActivity.java | 30 +- .../org/telegram/ui/SettingsBlockedUsers.java | 10 +- .../ui/SettingsChangeNameActivity.java | 12 +- .../ui/SettingsNotificationsActivity.java | 98 +- .../ui/SettingsWallpapersActivity.java | 25 +- .../org/telegram/ui/UserProfileActivity.java | 79 +- .../ui/Views/ActionBar/ActionBar.java | 15 +- .../ui/Views/ActionBar/ActionBarActivity.java | 30 +- .../ui/Views/ActionBar/ActionBarLayer.java | 29 +- .../ui/Views/ActionBar/ActionBarMenu.java | 4 +- .../ui/Views/ActionBar/ActionBarMenuItem.java | 27 +- .../org/telegram/ui/Views/AvatarUpdater.java | 3 +- .../telegram/ui/Views/BackupImageView.java | 2 - .../ui/Views/ChatActivityEnterView.java | 643 ++++++++ .../telegram/ui/Views/ColorPickerView.java | 14 +- .../java/org/telegram/ui/Views/EmojiView.java | 16 +- .../org/telegram/ui/Views/ImageReceiver.java | 17 +- .../ui/Views/MessageActionLayout.java | 4 +- .../telegram/ui/Views/NotificationView.java | 326 ----- .../org/telegram/ui/Views/ProgressView.java | 4 +- .../java/org/telegram/ui/Views/SeekBar.java | 6 +- .../ui/Views/SizeNotifierRelativeLayout.java | 14 +- .../org/telegram/ui/Views/TimerButton.java | 6 +- .../layout-ar/user_profile_phone_layout.xml | 11 + .../main/res/layout/popup_count_layout.xml | 16 + .../res/layout/popup_notification_layout.xml | 187 +++ .../res/layout/user_profile_phone_layout.xml | 11 + .../src/main/res/values-ar/strings.xml | 5 + .../src/main/res/values-de/strings.xml | 5 + .../src/main/res/values-es/strings.xml | 5 + .../src/main/res/values-it/strings.xml | 5 + .../src/main/res/values-nl/strings.xml | 5 + .../src/main/res/values-pt-rBR/strings.xml | 5 + .../src/main/res/values-pt-rPT/strings.xml | 5 + TMessagesProj/src/main/res/values/strings.xml | 5 + TMessagesProj/src/main/res/values/styles.xml | 11 +- 118 files changed, 4503 insertions(+), 3515 deletions(-) create mode 100644 TMessagesProj/src/main/java/org/telegram/android/AndroidUtilities.java rename TMessagesProj/src/main/java/org/telegram/{messenger => android}/AppStartReceiver.java (90%) rename TMessagesProj/src/main/java/org/telegram/{messenger => android}/AuthenticatorService.java (98%) rename TMessagesProj/src/main/java/org/telegram/{messenger => android}/ContactsController.java (98%) rename TMessagesProj/src/main/java/org/telegram/{messenger => android}/ContactsSyncAdapterService.java (96%) rename TMessagesProj/src/main/java/org/telegram/{messenger => android}/Emoji.java (97%) rename TMessagesProj/src/main/java/org/telegram/{messenger => android}/FastDateFormat.java (99%) rename TMessagesProj/src/main/java/org/telegram/{messenger => android}/GcmBroadcastReceiver.java (95%) rename TMessagesProj/src/main/java/org/telegram/{messenger => android}/LocaleController.java (95%) rename TMessagesProj/src/main/java/org/telegram/{messenger => android}/MediaController.java (98%) rename TMessagesProj/src/main/java/org/telegram/{messenger => android}/MessagesController.java (87%) rename TMessagesProj/src/main/java/org/telegram/{messenger => android}/MessagesStorage.java (89%) rename TMessagesProj/src/main/java/org/telegram/{messenger => android}/NativeLoader.java (98%) rename TMessagesProj/src/main/java/org/telegram/{messenger => android}/NotificationsService.java (94%) rename TMessagesProj/src/main/java/org/telegram/{messenger => android}/ScreenReceiver.java (77%) rename TMessagesProj/src/main/java/org/telegram/{messenger => android}/SmsListener.java (92%) create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/PopupNotificationActivity.java create mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Views/ChatActivityEnterView.java delete mode 100644 TMessagesProj/src/main/java/org/telegram/ui/Views/NotificationView.java create mode 100644 TMessagesProj/src/main/res/layout/popup_count_layout.xml create mode 100644 TMessagesProj/src/main/res/layout/popup_notification_layout.xml diff --git a/TMessagesProj/build.gradle b/TMessagesProj/build.gradle index a858c6659..5473fd2bd 100644 --- a/TMessagesProj/build.gradle +++ b/TMessagesProj/build.gradle @@ -3,10 +3,10 @@ buildscript { mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:0.11.+' + classpath 'com.android.tools.build:gradle:0.12.+' } } -apply plugin: 'android' +apply plugin: 'com.android.application' repositories { mavenCentral() @@ -26,7 +26,8 @@ android { compileSdkVersion 19 buildToolsVersion '19.1.0' - aaptOptions.useAaptPngCruncher = true + useAaptPngCruncher = true + useOldManifestMerger true signingConfigs { debug { @@ -81,7 +82,7 @@ android { defaultConfig { minSdkVersion 8 targetSdkVersion 19 - versionCode 268 - versionName "1.5.7" + versionCode 269 + versionName "1.5.8" } } diff --git a/TMessagesProj/config/debug/AndroidManifest.xml b/TMessagesProj/config/debug/AndroidManifest.xml index 8a10bfb38..6a08d6c12 100644 --- a/TMessagesProj/config/debug/AndroidManifest.xml +++ b/TMessagesProj/config/debug/AndroidManifest.xml @@ -33,7 +33,7 @@ diff --git a/TMessagesProj/config/release/AndroidManifest.xml b/TMessagesProj/config/release/AndroidManifest.xml index af9751457..a1ee70d33 100644 --- a/TMessagesProj/config/release/AndroidManifest.xml +++ b/TMessagesProj/config/release/AndroidManifest.xml @@ -33,7 +33,7 @@ diff --git a/TMessagesProj/jni/audio.c b/TMessagesProj/jni/audio.c index 70b6e2fc2..3ca0f1fb2 100644 --- a/TMessagesProj/jni/audio.c +++ b/TMessagesProj/jni/audio.c @@ -504,7 +504,7 @@ int writeFrame(uint8_t *framePcmBytes, unsigned int frameByteCount) { return 1; } -JNIEXPORT int Java_org_telegram_messenger_MediaController_startRecord(JNIEnv *env, jclass class, jstring path) { +JNIEXPORT int Java_org_telegram_android_MediaController_startRecord(JNIEnv *env, jclass class, jstring path) { const char *pathStr = (*env)->GetStringUTFChars(env, path, 0); int result = initRecorder(pathStr); @@ -516,12 +516,12 @@ JNIEXPORT int Java_org_telegram_messenger_MediaController_startRecord(JNIEnv *en return result; } -JNIEXPORT int Java_org_telegram_messenger_MediaController_writeFrame(JNIEnv *env, jclass class, jobject frame, jint len) { +JNIEXPORT int Java_org_telegram_android_MediaController_writeFrame(JNIEnv *env, jclass class, jobject frame, jint len) { jbyte *frameBytes = (*env)->GetDirectBufferAddress(env, frame); return writeFrame(frameBytes, len); } -JNIEXPORT void Java_org_telegram_messenger_MediaController_stopRecord(JNIEnv *env, jclass class) { +JNIEXPORT void Java_org_telegram_android_MediaController_stopRecord(JNIEnv *env, jclass class) { cleanupRecorder(); } @@ -618,22 +618,22 @@ void fillBuffer(uint8_t *buffer, int capacity, int *args) { } } -JNIEXPORT jlong Java_org_telegram_messenger_MediaController_getTotalPcmDuration(JNIEnv *env, jclass class) { +JNIEXPORT jlong Java_org_telegram_android_MediaController_getTotalPcmDuration(JNIEnv *env, jclass class) { return _totalPcmDuration; } -JNIEXPORT void Java_org_telegram_messenger_MediaController_readOpusFile(JNIEnv *env, jclass class, jobject buffer, jint capacity, jintArray args) { +JNIEXPORT void Java_org_telegram_android_MediaController_readOpusFile(JNIEnv *env, jclass class, jobject buffer, jint capacity, jintArray args) { jint *argsArr = (*env)->GetIntArrayElements(env, args, 0); jbyte *bufferBytes = (*env)->GetDirectBufferAddress(env, buffer); fillBuffer(bufferBytes, capacity, argsArr); (*env)->ReleaseIntArrayElements(env, args, argsArr, 0); } -JNIEXPORT int Java_org_telegram_messenger_MediaController_seekOpusFile(JNIEnv *env, jclass class, jfloat position) { +JNIEXPORT int Java_org_telegram_android_MediaController_seekOpusFile(JNIEnv *env, jclass class, jfloat position) { return seekPlayer(position); } -JNIEXPORT int Java_org_telegram_messenger_MediaController_openOpusFile(JNIEnv *env, jclass class, jstring path) { +JNIEXPORT int Java_org_telegram_android_MediaController_openOpusFile(JNIEnv *env, jclass class, jstring path) { const char *pathStr = (*env)->GetStringUTFChars(env, path, 0); int result = initPlayer(pathStr); @@ -645,11 +645,11 @@ JNIEXPORT int Java_org_telegram_messenger_MediaController_openOpusFile(JNIEnv *e return result; } -JNIEXPORT void Java_org_telegram_messenger_MediaController_closeOpusFile(JNIEnv *env, jclass class) { +JNIEXPORT void Java_org_telegram_android_MediaController_closeOpusFile(JNIEnv *env, jclass class) { cleanupPlayer(); } -JNIEXPORT int Java_org_telegram_messenger_MediaController_isOpusFile(JNIEnv *env, jclass class, jstring path) { +JNIEXPORT int Java_org_telegram_android_MediaController_isOpusFile(JNIEnv *env, jclass class, jstring path) { const char *pathStr = (*env)->GetStringUTFChars(env, path, 0); int result = 0; diff --git a/TMessagesProj/jni/jni.c b/TMessagesProj/jni/jni.c index 66a7976e3..4a43f84dc 100644 --- a/TMessagesProj/jni/jni.c +++ b/TMessagesProj/jni/jni.c @@ -30,67 +30,21 @@ void JNI_OnUnload(JavaVM *vm, void *reserved) { gifOnJNIUnload(vm, reserved); } -JNIEXPORT jbyteArray Java_org_telegram_messenger_Utilities_aesIgeEncryption(JNIEnv *env, jclass class, jbyteArray _what, jbyteArray _key, jbyteArray _iv, jboolean encrypt, jboolean changeIv, jint l) { - unsigned char *what = (unsigned char *)(*env)->GetByteArrayElements(env, _what, NULL); - unsigned char *key = (unsigned char *)(*env)->GetByteArrayElements(env, _key, NULL); - unsigned char *__iv = (unsigned char *)(*env)->GetByteArrayElements(env, _iv, NULL); - unsigned char *iv = 0; - - if (!changeIv) { - iv = (unsigned char *)malloc((*env)->GetArrayLength(env, _iv)); - memcpy(iv, __iv, (*env)->GetArrayLength(env, _iv)); - } else { - iv = __iv; - } - - int len = l == 0 ? (*env)->GetArrayLength(env, _what) : l; - AES_KEY akey; - if (!encrypt) { - AES_set_decrypt_key(key, (*env)->GetArrayLength(env, _key) * 8, &akey); - AES_ige_encrypt(what, what, len, &akey, iv, AES_DECRYPT); - } else { - AES_set_encrypt_key(key, (*env)->GetArrayLength(env, _key) * 8, &akey); - AES_ige_encrypt(what, what, len, &akey, iv, AES_ENCRYPT); - } - (*env)->ReleaseByteArrayElements(env, _what, what, 0); - (*env)->ReleaseByteArrayElements(env, _key, key, JNI_ABORT); - if (!changeIv) { - (*env)->ReleaseByteArrayElements(env, _iv, __iv, JNI_ABORT); - free(iv); - } else { - (*env)->ReleaseByteArrayElements(env, _iv, __iv, 0); - } - return _what; -} - -JNIEXPORT void Java_org_telegram_messenger_Utilities_aesIgeEncryption2(JNIEnv *env, jclass class, jobject _what, jbyteArray _key, jbyteArray _iv, jboolean encrypt, jboolean changeIv, jint l) { - jbyte *what = (*env)->GetDirectBufferAddress(env, _what); - unsigned char *key = (unsigned char *)(*env)->GetByteArrayElements(env, _key, NULL); - unsigned char *__iv = (unsigned char *)(*env)->GetByteArrayElements(env, _iv, NULL); - unsigned char *iv = 0; - - if (!changeIv) { - iv = (unsigned char *)malloc((*env)->GetArrayLength(env, _iv)); - memcpy(iv, __iv, (*env)->GetArrayLength(env, _iv)); - } else { - iv = __iv; - } +JNIEXPORT void Java_org_telegram_messenger_Utilities_aesIgeEncryption(JNIEnv *env, jclass class, jobject buffer, jbyteArray key, jbyteArray iv, jboolean encrypt, int offset, int length) { + jbyte *what = (*env)->GetDirectBufferAddress(env, buffer) + offset; + unsigned char *keyBuff = (unsigned char *)(*env)->GetByteArrayElements(env, key, NULL); + unsigned char *ivBuff = (unsigned char *)(*env)->GetByteArrayElements(env, iv, NULL); AES_KEY akey; if (!encrypt) { - AES_set_decrypt_key(key, (*env)->GetArrayLength(env, _key) * 8, &akey); - AES_ige_encrypt(what, what, l, &akey, iv, AES_DECRYPT); + AES_set_decrypt_key(keyBuff, 32 * 8, &akey); + AES_ige_encrypt(what, what, length, &akey, ivBuff, AES_DECRYPT); } else { - AES_set_encrypt_key(key, (*env)->GetArrayLength(env, _key) * 8, &akey); - AES_ige_encrypt(what, what, l, &akey, iv, AES_ENCRYPT); - } - (*env)->ReleaseByteArrayElements(env, _key, key, JNI_ABORT); - if (!changeIv) { - (*env)->ReleaseByteArrayElements(env, _iv, __iv, JNI_ABORT); - free(iv); - } else { - (*env)->ReleaseByteArrayElements(env, _iv, __iv, 0); + AES_set_encrypt_key(keyBuff, 32 * 8, &akey); + AES_ige_encrypt(what, what, length, &akey, ivBuff, AES_ENCRYPT); } + (*env)->ReleaseByteArrayElements(env, key, keyBuff, JNI_ABORT); + (*env)->ReleaseByteArrayElements(env, iv, ivBuff, 0); } uint64_t gcd(uint64_t a, uint64_t b){ diff --git a/TMessagesProj/jni/sqlite_cursor.c b/TMessagesProj/jni/sqlite_cursor.c index 655876d9c..de3f7469d 100755 --- a/TMessagesProj/jni/sqlite_cursor.c +++ b/TMessagesProj/jni/sqlite_cursor.c @@ -48,7 +48,7 @@ jstring Java_org_telegram_SQLite_SQLiteCursor_columnStringValue(JNIEnv *env, job } jbyteArray Java_org_telegram_SQLite_SQLiteCursor_columnByteArrayValue(JNIEnv *env, jobject object, int statementHandle, int columnIndex) { - sqlite3_stmt *handle = (sqlite3_stmt *)statementHandle; + sqlite3_stmt *handle = (sqlite3_stmt *)statementHandle; void *buf = sqlite3_column_blob(handle, columnIndex); int length = sqlite3_column_bytes(handle, columnIndex); if (buf != 0 && length > 0) { @@ -58,3 +58,22 @@ jbyteArray Java_org_telegram_SQLite_SQLiteCursor_columnByteArrayValue(JNIEnv *en } return 0; } + +int Java_org_telegram_SQLite_SQLiteCursor_columnByteArrayLength(JNIEnv *env, jobject object, int statementHandle, int columnIndex) { + return sqlite3_column_bytes((sqlite3_stmt *)statementHandle, columnIndex); +} + +int Java_org_telegram_SQLite_SQLiteCursor_columnByteBufferValue(JNIEnv *env, jobject object, int statementHandle, int columnIndex, jobject buffer) { + if (!buffer) { + return 0; + } + sqlite3_stmt *handle = (sqlite3_stmt *)statementHandle; + void *buf = sqlite3_column_blob(handle, columnIndex); + int length = sqlite3_column_bytes(handle, columnIndex); + if (buf != 0 && length > 0) { + jbyte *byteBuff = (*env)->GetDirectBufferAddress(env, buffer); + memcpy(byteBuff, buf, length); + return length; + } + return 0; +} diff --git a/TMessagesProj/jni/sqlite_statement.c b/TMessagesProj/jni/sqlite_statement.c index f3d110030..1090de3db 100755 --- a/TMessagesProj/jni/sqlite_statement.c +++ b/TMessagesProj/jni/sqlite_statement.c @@ -62,20 +62,14 @@ void Java_org_telegram_SQLite_SQLitePreparedStatement_finalize(JNIEnv *env, jobj } } -void Java_org_telegram_SQLite_SQLitePreparedStatement_bindByteArray(JNIEnv *env, jobject object, int statementHandle, int index, jbyteArray value) { +void Java_org_telegram_SQLite_SQLitePreparedStatement_bindByteBuffer(JNIEnv *env, jobject object, int statementHandle, int index, jobject value, int length) { sqlite3_stmt *handle = (sqlite3_stmt *)statementHandle; - - const void *buf = (*env)->GetByteArrayElements(env, value, 0); - int length = (*env)->GetArrayLength(env, value); - + jbyte *buf = (*env)->GetDirectBufferAddress(env, value); + int errcode = sqlite3_bind_blob(handle, index, buf, length, SQLITE_STATIC); if (SQLITE_OK != errcode) { throw_sqlite3_exception(env, sqlite3_db_handle(handle), errcode); } - - if (buf != 0) { - (*env)->ReleaseByteArrayElements(env, value, buf, 0); - } } void Java_org_telegram_SQLite_SQLitePreparedStatement_bindString(JNIEnv *env, jobject object, int statementHandle, int index, jstring value) { diff --git a/TMessagesProj/libs/armeabi-v7a/libtmessages.so b/TMessagesProj/libs/armeabi-v7a/libtmessages.so index 9d9f733847a0755210f7b7f53fa1ef741eb68c4d..078cb27f24726ff3d6c0e9c7455507a610b52e19 100755 GIT binary patch delta 58923 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

%*=hF~ z|KR_Vt-Uj6Xkh73X`pZ5#r?M0%LlyXsFU0mO!&?I(tvI0_X9VEC;24ss=?ilmj-UH zx#Qu!f$8R-PjcU2zwLmz<0SW$wz=lKliklGJ=ep3)H8P<|3mZpOZlHR_~W~xF#nm$ zv!R&ZxF3tNC5N7z?LOLWGeaBBbpO?6GeT$0bsu4~?<+Mg%W+?9-&Sfqm*c+6{_=I9 znP<7}>Z+`+?HXIl1nO`8%bW(DHfi#~ijlg-$u&JvY|bc+G*G zaoNXh4}|WS@4jK=Rh4(|8Cr1mMxU|q>90rjRdwh5%3ks-JL^|=_pj`N%3tPJWRAMV zeYD^BmACqpz3^9d#h(uTqFSBz{4(3X;$PZ%RKwQUHBjI7!NA;?`EO0^wnf2U{5sip zmpo?+{pT9@>Cyh&MSJ|gl{S@H34=kEEo^qE%q6ffN)xyX zRD*D}U6nnu$GvC_V_!Akn-Uke-|wO2>-RQDh$QH z<#S0GR6!^e3s`o&%Kbw8m#KwN{3|SbxoWYvLT$C!sFJ_j<6lKj6~HP#8Fu0bHrrL{ zS9|^vbu)b9AnO5Y`9F7?9IvlCQS^iTfA*&|g2B%)XK<7l2eQw3vw(p?Ir zz{EIVlS*{`UzWCepv;wxXK1?>2Aktm!Wz5xfc#h=1R+Z;yyA()K9-GP#T1&~^db z_|uTz`j8dDl#{w7(KBIafb~kLEZK%%8I=ll0no8wf)=h`lVvMk@cE5!qQA#9E@RYSLA z>5*{6?h~5^W{uL}8Ke9p$S_sz(b^*$N(Mb%ZFfV-AaSxJ45|buHIIwfg%LYnY=&mz z6k(J~nkw<1Q58_)ms$3+Ds`H+y-;@0IR7ycF`$y6L`<~oCRJ%MsH!6VhwQFMcy%i2 znqySYbe*mnN(I_xXuAalSGrZ}vDywonS@Dc+D?EnH2$pP#W7yxoTLM?pj;eUV8f3? z{=ze~e?F|o&d=6%E|ei~oGDzU(uM4JThG?vU9kBKQ>C4&?Gz}pehX|)F;(mNmcQQ! z;*fy+3v`B_d|^-(!7K{QDApOIL7C0fSCPSZQ)OHm@rM$Bp^zR4mumk$D3d$kI&H_n z;L0OZ{|(yih0Te6Q*F9Qd$hwXKMeVo{88HqHqVYx^>=E!7Rp>`y-V9cD3{wU5xY}t zdZg-4q>Fz}KUnVX#5qa(&asc6NI5*}1Nuz589 z%fx{8&x#6L6)KAf`WhKZL}Cv-4>fv^51lLzC|h$vHi7{gR7p!MwM125tpk5%;>?YOlfG(&GuAJ>w zOX`K=RC;&na_D0fgT6R>6dH{p==ojOq`C^(u3><59Vl98#3r;C3)d$%w_ zl^w4$DuFU7l|`1P#bv5DVh={b6VfH#TGc7!j>tFxa?92O2?(nGh{u*$5|QO)u~CI1 zcE80HDltQc=UH5)DkFBi#RgS)l7v5_l1~;cQ}q^ussqaE*l5|$DD@kiPXnZDj!@iz zSOo_x)~oi2-DNSL2BA#G%v1JSldB3!%WExCu~V@bilW(&EqQ^EhE!T?RD%`+DlU7k zzj)V>KM6|u>}F{(Y zEl!Qt4N&s$gObj3w&cexpFel6f9-6i>X;`9=_)7@!(!8tjB_COcr8K_q@FABnp8QI zjB24wwjL;_U2mSYH$llyGoZS~X7Y9vM1}&&e&O$pcx;P!RL<8KRbQ+NXobP1D3x-F z&N!)164G@R*QzEVlhSj!(4)$(giNj`Ar(#k9c1=z6EZg{i}(6_cMkdEevjRp;8!Wv z=#0ZK*l1Hl*TS{YD*F$6{hdTiDU*mU)qfM@Cbg}6ufHAtl7+g0HE{LpbXERm!s)Sk zAw!iaL%YhZ@`R1is!Zwl)leExZ_!VeTaJ2_x=0c_REJPj0W77U-iV#ISo}GfSq!Ka zAuTPqThh%^Re#s%>V#By;X~S1P=;zt#O@JNu|c7qW#V`k2kSCXNI)8t$&(`X2&HO- zR7kjO2e;>z-Kg4OH+DxPTr;40u%*EKNAz4;2qnJ?D08H~hWyx=icML56xe`6?$Nf^ zLb|wnsnDUqk3+gD=?O@@Iw6xV>nTXfJA@2b+S8B<7F%4dS}g`tO1%yb2)X*T3wfT9 zyi90U<40P?6-kZQ-iVzG7j7T&7eEDz zVI?esOW*=1UEc{Meb{1?%5B4@XDgvBZ|??ddZ5=Y4qCAB<-Ps_GU$NPLbXx2LJeBv zy8p^ve>UMM9r$yDk^Gi~H>i4ORN7V0vR5d_ChcEpak({dcM@+! zlxh;v@-AVp(XSFVYmXcuPq!+B^gx%8NtXM**kml^{Garpp2a0_pwgy#pfsS*;xd)_ zk*>f(C>3n6$TOsm#a^xoEpoNA=wGHbiQ}0lmHCOzsL5iJGCtLI1C$oEN9_F7fBU2o03P+A(d1FmtYoSk9^RUwp&0+vn7d$qq;$RthNCH8Vv zDty+Va(3&AWPY#X6+x?O$|D{Npk%luVhgPTevkyq)K(~V%8xpOR484W1I2#0{Z0-L^O{YLE8NVpLr;q@xnVx!7{(!xTqxhi&9{z26# zWbZGJ6*`o^!YL8BtP1I(ej#1tbqRwi4a(%{a*N%l+D7Q`twQ1_$LoTMq1X*jh9r5U z#A{LtN=3RYyHRaP(BVCha{Q`4;*mT`M=XGnut7-0l14*@q+f`C=@F2Ewg|B^5_P&F zC>3pjQc=ekVL%l?sn9~pZdBQ0wVe-n{?BBv98Ibd7H{K8r)4*)qH#K6Ih2eWlJ;3g zt^6Z(0TobMwl!i`jn@U%Ln*MsvYS-WQQFRe62CHHw?nS~T;-B=KpvFk*EbQeH>Vt} z6XwCL|8UWP(xT#se?!FXh}gXmJIO2Yf=V->(#2-1b0-PoRM!+p&nBnrWBn6R9MWa^ z7J2jntuC`{9!^_iN1Q700xDI=kW^cClS(}Xn*#cTjiXe0s>EBX>MgS22)X(dPuKpX z$3iAy?s1U{h(i*T&6J1^Re3yQ)+VMy4h-2sDp~|bu;;gkO$$m-5dY;$39;j5L3*%V zC=EMNSg#6%_!piOnJd514NS@OYmbUd?a>8gjM7h$giYLFXgl##vDc~`i%qIEVyn}{ zzftu;>9Le7ovzFxU$I!MS52qu@J%qdnq_{5&M(0~TL7lfXbc@2j)h(|o!2ioi z)g@$>Z=4V5G0(-iNAjWcL=#*i*MCQ$PFR114ye9zpFf!v7XMD{psIsO*lkd{v>PU3 z4_e_(YC$paSYEYPN&H4tdbQ4H5K8={-(%DAVj&fZE7@mVj4H2{x{NQnZ_L$C=-7iRtqn-*3< zIrle+P58!$-61v=D6i7t3!qeRlaO>_A@LI)(Ek29ajZ^Jj=xI;kIE7fArDG{RbrE2 zgGG)~)!J6D_46Tr;zPOt8BpQ}BlcD(ldbz<$hYT}k3jAfw+b23axf?C7)}%R!D^lx~=uUR(b!eGpvCUko+Hs$l(#DQGt@L#s5@Qxf3=Xt9pgB z$YSF$D!*6T7O|TmwngSp-7X2|BqUrjUS;my=kNZMhWT+wLETWsGV42RTHXSsg+`xF zm75(Y^B!Wv7 z>=!yz!k`Xl5VC%^9fV|9g@sU-Pm_=Yxo!zxq1uIOCMvH-{AY3BAWTtlV}$EBkmVK@($az%I$jNw{U!NW@pq}BG{`p&s{RBW zkTXjHMyrz3_gk0atxz)T%!X7X`%IltIg|?YK|_

^rMPAMXsvCa}w;kYXyldVTcLH)&$g4I>xAESDOlvjDRR3H$o>Tr0;$oRbk*wrQ> z%d11kYUs3Vo|KmCx2}3=PzuZuQcxgbZxm8c#Wj#F&b?OR@%D?wwJN_+{zlt#Y73P7{keDH2%M+}h19s|Pr3!0U~sidWi5ow zla*tUgs)XSi^V=!b>9cq#Hnrfi|tYgRgkk@jgX$GhgJ`YO}=>#NIXL&KPWbbRN?CJ ze$|d6`y;-Kg_6MWcLJzsar9V9x}yk5__#Gg)#{f-w~U+@vbhY49b{yK?zsyNjUe4osf%H@kiRu|5)ra z)!Qx0kI9$+ZwaVZRTg>oL&&6x`;X2j8_Jtd-u;qrv?@O+j8oaRK{!nndxRWDM?ebP zDkMBG60$M%Cy4D)IirP4$|H1mPvRgIV2kVsxijJnJRgqdH%d@J1DUNo<#2 zRs53-X+g#-y6Xy{RH*iK9dVnG4JGLfD}l;?PsdB@)aimy!nZ)_`ozsTT_%*Ctb)e- zJTJ&RV7<;$J@YXNw1~Ql0~;dDvn=C7vt(aVq6}NY_^h`O0Ohkd`mF z^njidP||NL5@x8hTZKt#uz~`qK;`Y&3{}z{;y+OZ@6xvCPmnMA)z*a)kgBRHb%cy6 zVU|j%6Q-youRu9+y(aby)w)N>u{#WzoK1TV_|rBI`7`&4ze@#$Tx`7i#pe5gL1CO) zU^@sCRk>T}QfVU&%JNH6abv_IUS%IC^r(vQkOH>~X}LN|{1a5#(ZV>DHd*|m)Rrk? z$EfycLWjyb2C`Arr$UCL!(x=$Dr6G(3Az6FPlr@s!EsUnCdtB?c+mB=$4dk@o^**2 z&kF~Ti^?{kOtzDSDXRRGgZ|u3#`FxaJ*s^UWT)(aGUnNHwVeg!d&LYW{u?9yn)Rx8 zu3sW@0?N@5;?B}`7VLkIuT(6XS1h1pv;bOHHSwqGOME(=akdUmnWqabu*ic8AuV;B zD@;%=dBS*Aem9aK;=QnzX3MK`S}v)cAcR94xLf&ABAgG@?DXZK}nbc)1)OZ9TrEz3$5@b z*0sc2q2m6ed#n%297$eCPZB>HO2GwC8dCh1gMPzLKobt}2w0P`No`%E3+{rFpdZRu zRWBwU7m;mu>-fEuLcVOeN5`v!GITlj>UjBo6>=}QMCJmk>TeRCZ_}alOd7Nb$d>>a z(<&j4)gIJ#Rke;-38ib5MOyffZec!@be>0q4pm$u^PNF3+ahmA>o0g zI^TL|RiGD#tnZ#DAU)Aurz4gG63(d?iXE)i@%t_EKF~59zZy!KQ+DZv;ROQf`Oi<$0 zS^oT`M8v<(vKv)WK@O1ugv4QcV?kmc2}3J-R&oYlevRk23MmfS26*Q$)5*rQd= zb9yd#{vl(^bNp8E=YXKGOY?aFoh*+bH4Bs?1l!=KeqPRdI|^ z3GEWFl6N_Uyhv!VL3Ik*fLh-WMyd7=A#csSDe;1;Ldagf#Io5*-_{jrfif9e-_h~f zEb@HdT^;U$4543@;PAZ7OQD-3;#!scKIC#4_kq|=s$EEr^nWN!REeMHt}KNz1a%R+ z8+N`m(!tzYPm}N^q@bAF)xQ!g)Oo*Lz}_-cb$=d9%xOH&-9Q~Y?TB&<@#LP z$zSRWgfjU`p^Rm*_;Yq_6S5l0zJk2SpoB7{Uq|x$M#nFMlJ8&-z7WLE^`#P5X4kQuga~jzQsCRSTtIc?Wd* z3MdsXgH}MrK^?HfBCp*J>5R4-Lsoc-ZOCfzpkv5N*bk*E#g?8(j>cZ;R86tMk!pcc z$eeNuk5IWIgkw};0_5D#FQj1wqlf%fhIu$7qX4uvh(yTYGjGfgElg0wN#gHOapQ#v zYU@#uvCm0{jBz=XG2RGer%axp^IHO?r3%WrPnZZfpj23lQjVj!|C8%*_0f=%j>D@H z42n$)#g+)*)l7lp7Z$Sf^-b0J^*|ZA#AC#t>;Cje zIsQ}~;Kf4YCRNf4oFbA&W(QSE}wo9Q@sPDK)fl!9PbAq-V zu>B4G)+|HY9Z+85_4j2)62O(Sk5DaVXuAmpS01Oz<_O2A+#JX~Vkxv{z1Xy*{w#)w zE^qTmIDcN3E9AQ)i)+=AbFi7bN#{y@m)dfkj$e3z*bcv{&DR-LL+ODgm`Y7sBDPQp z6o2W`whJLApq`6_d{OaRZ6_B%(kH?G*ZDgiu~`*c=L-{6)+ItNau(y%#>*sM)_*Gw zc{4HLa>x#sbR~a!M+U7|NdmrnzFNq+y+qEz1aAurbvPY@nDwrMI!b>Im7jrNx~JX>PAQl(r(rTq(I3~m`Xtz zP}X^!<LMFART*r4nYlDOG-BBL2X6u$ngia_mO}ItK@)ELMTO#(LW%EVCtvbB; zHl1-Hl#DAQ_ChFMUe#OVaxNqv&+U47X5E3!Go_-tqyk*!O8%m|t_oT$fYP$sh`kLK z{AoxIi$b*4R zl{#V3Jvw1Al&-20o5`2IMEnD)&SFqCSgcnYBmUbW{z54rc%Q^?QbqR*xs3l!r_YDg z?fj{y-}2zqNsIML329-wW%Kx4D6{whUGpwjLc-Jswe5vcp)^>Ce^s^ik6TKQVJAQd z&xX>o3!(H($K&E3RQ@gEV3s%3>4Pfsx!oMeMLsXj`~C;W<_NthSq=R3u@gWnZn*aCDL&2R2T9P7OjCqq@6 zw^4#BPz`EBo|oK46KX;2XdCK9gUD;RjKrBGw&XU_Zg3lQD2Vc3b{n;*8+nZczqn=mYextmdLQ&4UZX*vBqY6}sYEckvL<^7i@LxQ8jBtjB z|J~7Jl$`1@5>NLS8)tir)H6NCHdHvr!~Z7iF}9*XlsMO8c#(REn^k&cOhoUL;YcvN zMRSuq{D+x_5r-s#8!aJ0d5*`Z%Q64b<{3Y_>MW13gg(um=P^>w@fc0#nvHFq88HQU z6p(LzD(;#~EVpX|?utt-_o=x3C6|fYW1OB4ZLAv^ZA^zJAo;YsN3S9&|IPSVWAERh zjq}hu?pWhObfytwjIqTSuef533HOt}(`j6Kezb8FI&Vg-@jzd+aSQHMak0jIv9ZRD zuSXj)^ba_H&ddLc%q9_eDmoJVPcysmaAv>A>v<~o`4A2I|IKU4FKf2BA=-#u9Bu6J z#v1%)ow4`wXybr6=}pfOk0b=W{(iT|aCkh@H%2PVK_zGbD)^LX3ENNy+JXjA!U&I% zhVoD`O6_$U4V`Xd0q!bPk2+8fGUAyHCXdaTa!{^+(i&lc-9PQNeOaN1&x^G=O6 z=A$dnRY*S4v+_AGo!;gD$Ul=`1Gw=`Iy67pSidaVxUU{R+*iO)&<4Uz;6I~33H_Ol z`Zw*pl>FzRv(TZ>7{ZT46Hc2RZA`*36-`ISp+ld3T7T#><6ZY7w%{1EIN07{~FOONTxMNxDnLwhxPQ;~x&kDK=mE&@;~e$)65;l?_XlM{gCPVpNJM z&_Yy+mY}3CqXV-xyNxn>cLAzI)u;{yPz&0KI#4Itg0`VP6h_8KkKc$J$&jKXOh@n3+hI_D2$9z6oQga3Q9xiC$P2 zswcr8z!gMor~`GOZKw|oqPQdIH{?ZWC=+F)TvULHQ7I}%3y?xfPz|a_0n~!pP&?{G zTTnOZJ%UNlk7E!ym{A^-h>}q%%0O8t2jw#H4}CfZSOAeVT8KaY3nHHcqZGGnu=1%O zjw2FhK_pHB{*|~7t+m=QOae(PSA-w|hZe*}-2AMk_34ZxR#@G*osmrYaJwRI$Jj%a zFlz)Z5~CvSCVFLb#NCG5e*_uIr~6Q*isJ_Xa`BW;KmPm|ZPq7@ z|2XY59ODlAEBuop{t5W&;V|sUxDOSaddNT9FtQH04Ts;z|JmTb*~We7Q$?mnMvR4# zIHWbIagUGqr?C+p6>-<&pB$-Z0Xx)$h&zD)#E9F0|Iv~7Uff=*|M6%c(xFcRnNErr z?f6fQB<{j(wJgqN6jM3z-iDvBHxd?xG65ZIrxMo##ZHWDugSxo8SCE=FH=*0`dI~sKB-JTt_?;y%tYB}+YfFdg#t1nh2%t7OS*a#Kusu! zT2L!$L+z*&4bmf9;3BT_51^&zN6Yl2b>mr{M^OkWMoUlwYDe3UhjUdL%0We_90gG~ z8bsa+?B%E$1yBd-M>!M84^^Q6>O^7WJ(@CXbb8`$&+aaDnqrX74@KmDfA>NMYX6M_51n9n?h!&1XZFo)Pv%t z(rQ$I%8)`0s0H<-%xR=S)u$Y-fYMPeDntskqJET;ia#nxRmk7MKU+{AN}SGa zh;ooZZD=d%MV=W{2IZkrREau}<5<$5a#V@xP&ED2P0y+}S zL(f!@UwO1~;pA9jb6<=x6}{OXV?6(34F9oBjIorw?cw7gP747~?|r_&4F{ zTjPx52*2XGIOFRlINfo=dxg4Ph2NSt^rDF7x0Or#@7d&^av z4j&`lX)(rioAnOxCKcLF;a3oT!T~>lIObEsGdbBE$**934p((yqj~7MkLm4sR091A zZ9u0J{~3B{620;{m0g2I?BNJX4=u9C8r$iiWmJ0pTTbIFcpQ3^p8RApy+@pf(C3_q z@ARJ!&9OfAZv5V}1rd z5q=pxLCa1;>nQwmexmbq3Yj`8&Uhv&&Nv18B(&_(IO8PpxG$T^GOYds-;xm--ZMZ& z7{gV&7*7gZhTkV-6ir0=+{m0;<&8B)QNZVKI*silo_7RwoaxM@g5=_ zzanouI-4Q8l20g?uOdt>W$ZlTqg~x1u+cRQR&NpoBc#Mju(tPJ_&+(@u<{I2D z8^(Q?a3z5CPwP91-(t(vqBz3R2+LtS{&$)uZSvggU(bd6$yhEjZ?h?IuU!8ccR09f zVGGK95gU47Ijlxq#4E(ECSDLbfZFhD755w5XLn%Z=2b$YjyMb9M#&RaAw}3W?8G;@ zNv|P68_K}bgS`L3jW(f@*LfmUzP7Qt+kgxbVL?UYsX+8^A;5**!VBT6D5m&AEU6>&j%$8GFtbQs^ScKkfO+k@q%l&t)uo$7SS%JjSv*m+`L~UB-1^xr`IOaT#NJT*gDD^Igwv{)GXz zkyu8joI}~D3jO-y*v>fq-^l-emGS>DUoPr9awlJU_8;$Ubyr=bMgUhbu|*U&k@mlK1>u$`7Yo@~d=* z?jZiVI735|em<0)HT!Trz2=ecd#3O!2dBU9Im-Fr8SLv5_~mc&s`owPMhuVGXWkOw z(3ijRd+-y_*b%En9=g@xCdjKSLJ4OcP* zX5ObB&#VWA)jInZdDwo=e9^G6Dmc>IEo1upu)!*h_}w@xuZ7yre&(&_Up}R<%l_?g zamD)j$HS+s`bgvOK8Y*zp-)T1oBQSo!@S#$)RXD<>kc<)Q>5T|T-*Y!`o15xGAG;A9m-f*A8z=K{oMa9T|7|4m z@1J6(V6lWjL&x-_zH zr@Fb*{K#W`{(;k&@8Rx(C*F^ah&84@7;S7`$cdj@)Csu%#S`=G{A%kev<|;Z;h0{I zjGW+3F;Do+bHrKcWL5RQlT{X3RsXMKBZV#{?i2}++P zL+N^Xeya@Qk*MGpe;3W^M!iTr>D_K)8DBrhr|-+dQ#|{t!|qJt9Qx!%(urL#%$+za zPSG&`l40&LH;?}geJX|pqz@}>;V}QoVeaZ-?%H8)@34X!@c*8fBcGOGaoT=%r^;E? zV{GPzRX#n#TDTSrw6@#xlkNWl?^C5; diff --git a/TMessagesProj/libs/armeabi/libtmessages.so b/TMessagesProj/libs/armeabi/libtmessages.so index 13a6c5a3c1ef39e6646e8789f5d96701eda03124..710cbf15b29005e57c24d21a627fdde4018c555f 100755 GIT binary patch delta 73920 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 z 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

>WaRX26%5WU2jw1%Y(Bz5jx; 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

;!Sac}qmw=a$^PvC{U;^L> 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 Wg44RGdd?cBBBSZ`Q@Wi!WBwO_)l6;x diff --git a/TMessagesProj/src/main/AndroidManifest.xml b/TMessagesProj/src/main/AndroidManifest.xml index 71e7bb9cc..894e88eea 100644 --- a/TMessagesProj/src/main/AndroidManifest.xml +++ b/TMessagesProj/src/main/AndroidManifest.xml @@ -58,6 +58,7 @@ + @@ -100,14 +101,23 @@ android:configChanges="keyboard|keyboardHidden|orientation|screenSize" android:screenOrientation="portrait"> + + - + - @@ -116,7 +126,7 @@ android:resource="@xml/auth"/> - @@ -127,15 +137,22 @@ android:resource="@xml/contacts" /> - + - + + + + + + + + diff --git a/TMessagesProj/src/main/java/org/telegram/SQLite/SQLiteCursor.java b/TMessagesProj/src/main/java/org/telegram/SQLite/SQLiteCursor.java index d03d52ebe..48bd87778 100755 --- a/TMessagesProj/src/main/java/org/telegram/SQLite/SQLiteCursor.java +++ b/TMessagesProj/src/main/java/org/telegram/SQLite/SQLiteCursor.java @@ -10,6 +10,8 @@ package org.telegram.SQLite; import org.telegram.messenger.FileLog; +import java.nio.ByteBuffer; + public class SQLiteCursor { public static final int FIELD_TYPE_INT = 1; @@ -55,28 +57,21 @@ public class SQLiteCursor { return columnByteArrayValue(preparedStatement.getStatementHandle(), columnIndex); } + public int byteArrayLength(int columnIndex) throws SQLiteException { + checkRow(); + return columnByteArrayLength(preparedStatement.getStatementHandle(), columnIndex); + } + + public int byteBufferValue(int columnIndex, ByteBuffer buffer) throws SQLiteException { + checkRow(); + return columnByteBufferValue(preparedStatement.getStatementHandle(), columnIndex, buffer); + } + public int getTypeOf(int columnIndex) throws SQLiteException { checkRow(); return columnType(preparedStatement.getStatementHandle(), columnIndex); } - public Object objectValue(int columnIndex) throws SQLiteException { - checkRow(); - - int type = columnType(preparedStatement.getStatementHandle(), columnIndex); - switch (type) { - case FIELD_TYPE_INT: - return intValue(columnIndex); - case FIELD_TYPE_BYTEARRAY: - return byteArrayValue(columnIndex); - case FIELD_TYPE_FLOAT: - return doubleValue(columnIndex); - case FIELD_TYPE_STRING: - return stringValue(columnIndex); - } - return null; - } - public boolean next() throws SQLiteException { int res = preparedStatement.step(preparedStatement.getStatementHandle()); if(res == -1) { @@ -122,4 +117,6 @@ public class SQLiteCursor { native double columnDoubleValue(int statementHandle, int columnIndex); native String columnStringValue(int statementHandle, int columnIndex); native byte[] columnByteArrayValue(int statementHandle, int columnIndex); + native int columnByteArrayLength(int statementHandle, int columnIndex); + native int columnByteBufferValue(int statementHandle, int columnIndex, ByteBuffer buffer); } diff --git a/TMessagesProj/src/main/java/org/telegram/SQLite/SQLitePreparedStatement.java b/TMessagesProj/src/main/java/org/telegram/SQLite/SQLitePreparedStatement.java index dc208834d..6335d93b8 100755 --- a/TMessagesProj/src/main/java/org/telegram/SQLite/SQLitePreparedStatement.java +++ b/TMessagesProj/src/main/java/org/telegram/SQLite/SQLitePreparedStatement.java @@ -10,6 +10,8 @@ package org.telegram.SQLite; import org.telegram.messenger.FileLog; +import java.nio.ByteBuffer; + public class SQLitePreparedStatement { private boolean isFinalized = false; private int sqliteStatementHandle; @@ -26,35 +28,34 @@ public class SQLitePreparedStatement { sqliteStatementHandle = prepare(db.getSQLiteHandle(), sql); } - public SQLiteCursor query(Object[] args) throws SQLiteException { - if (args == null || args.length != queryArgsCount) { - throw new IllegalArgumentException(); - } - checkFinalized(); + public SQLiteCursor query(Object[] args) throws SQLiteException { + if (args == null || args.length != queryArgsCount) { + throw new IllegalArgumentException(); + } - reset(sqliteStatementHandle); + checkFinalized(); - int i = 1; - for (Object obj : args) { - if (obj == null) { - bindNull(sqliteStatementHandle, i); - } else if (obj instanceof Integer) { - bindInt(sqliteStatementHandle, i, (Integer)obj); - } else if (obj instanceof Double) { - bindDouble(sqliteStatementHandle, i, (Double)obj); - } else if (obj instanceof String) { - bindString(sqliteStatementHandle, i, (String)obj); - } else if (obj instanceof byte[]) { - bindByteArray(sqliteStatementHandle, i, (byte[])obj); - } else { - throw new IllegalArgumentException(); - } - i++; - } + reset(sqliteStatementHandle); - return new SQLiteCursor(this); - } + int i = 1; + for (Object obj : args) { + if (obj == null) { + bindNull(sqliteStatementHandle, i); + } else if (obj instanceof Integer) { + bindInt(sqliteStatementHandle, i, (Integer)obj); + } else if (obj instanceof Double) { + bindDouble(sqliteStatementHandle, i, (Double)obj); + } else if (obj instanceof String) { + bindString(sqliteStatementHandle, i, (String)obj); + } else { + throw new IllegalArgumentException(); + } + i++; + } + + return new SQLiteCursor(this); + } public int step() throws SQLiteException { return step(sqliteStatementHandle); @@ -102,8 +103,8 @@ public class SQLitePreparedStatement { bindDouble(sqliteStatementHandle, index, value); } - public void bindByteArray(int index, byte[] value) throws SQLiteException { - bindByteArray(sqliteStatementHandle, index, value); + public void bindByteBuffer(int index, ByteBuffer value) throws SQLiteException { + bindByteBuffer(sqliteStatementHandle, index, value, value.limit()); } public void bindString(int index, String value) throws SQLiteException { @@ -114,7 +115,7 @@ public class SQLitePreparedStatement { bindLong(sqliteStatementHandle, index, value); } - native void bindByteArray(int statementHandle, int index, byte[] value) throws SQLiteException; + native void bindByteBuffer(int statementHandle, int index, ByteBuffer value, int length) throws SQLiteException; native void bindString(int statementHandle, int index, String value) throws SQLiteException; native void bindInt(int statementHandle, int index, int value) throws SQLiteException; native void bindLong(int statementHandle, int index, long value) throws SQLiteException; diff --git a/TMessagesProj/src/main/java/org/telegram/android/AndroidUtilities.java b/TMessagesProj/src/main/java/org/telegram/android/AndroidUtilities.java new file mode 100644 index 000000000..298e2ad3d --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/android/AndroidUtilities.java @@ -0,0 +1,216 @@ +/* + * This is the source code of Telegram for Android v. 1.4.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-2014. + */ + +package org.telegram.android; + +import android.app.Activity; +import android.content.Context; +import android.content.pm.ActivityInfo; +import android.content.res.Configuration; +import android.graphics.Point; +import android.graphics.Typeface; +import android.os.Build; +import android.os.Environment; +import android.view.Display; +import android.view.Surface; +import android.view.View; +import android.view.WindowManager; +import android.view.inputmethod.InputMethodManager; + +import org.telegram.messenger.FileLog; +import org.telegram.ui.ApplicationLoader; + +import java.io.File; +import java.util.Hashtable; + +public class AndroidUtilities { + private static final Hashtable typefaceCache = new Hashtable(); + private static int prevOrientation = -10; + private static boolean waitingForSms = false; + private static final Integer smsLock = 2; + public static int externalCacheNotAvailableState = 0; + + public static int statusBarHeight = 0; + public static float density = 1; + public static Point displaySize = new Point(); + + static { + density = ApplicationLoader.applicationContext.getResources().getDisplayMetrics().density; + checkDisplaySize(); + } + + public static void lockOrientation(Activity activity) { + if (prevOrientation != -10) { + return; + } + try { + prevOrientation = activity.getRequestedOrientation(); + WindowManager manager = (WindowManager)activity.getSystemService(Activity.WINDOW_SERVICE); + if (manager != null && manager.getDefaultDisplay() != null) { + int rotation = manager.getDefaultDisplay().getRotation(); + int orientation = activity.getResources().getConfiguration().orientation; + + if (rotation == Surface.ROTATION_270) { + if (orientation == Configuration.ORIENTATION_PORTRAIT) { + activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); + } else { + if (Build.VERSION.SDK_INT >= 9) { + activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE); + } else { + activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); + } + } + } else if (rotation == Surface.ROTATION_90) { + if (orientation == Configuration.ORIENTATION_PORTRAIT) { + if (Build.VERSION.SDK_INT >= 9) { + activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT); + } else { + activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); + } + } else { + activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); + } + } else if (rotation == Surface.ROTATION_0) { + if (orientation == Configuration.ORIENTATION_LANDSCAPE) { + activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); + } else { + activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); + } + } else { + if (orientation == Configuration.ORIENTATION_LANDSCAPE) { + if (Build.VERSION.SDK_INT >= 9) { + activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE); + } else { + activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); + } + } else { + if (Build.VERSION.SDK_INT >= 9) { + activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT); + } else { + activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); + } + } + } + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + + public static void unlockOrientation(Activity activity) { + try { + if (prevOrientation != -10) { + activity.setRequestedOrientation(prevOrientation); + prevOrientation = -10; + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + + public static Typeface getTypeface(String assetPath) { + synchronized (typefaceCache) { + if (!typefaceCache.containsKey(assetPath)) { + try { + Typeface t = Typeface.createFromAsset(ApplicationLoader.applicationContext.getAssets(), assetPath); + typefaceCache.put(assetPath, t); + } catch (Exception e) { + FileLog.e("Typefaces", "Could not get typeface '" + assetPath + "' because " + e.getMessage()); + return null; + } + } + return typefaceCache.get(assetPath); + } + } + + public static boolean isWaitingForSms() { + boolean value = false; + synchronized (smsLock) { + value = waitingForSms; + } + return value; + } + + public static void setWaitingForSms(boolean value) { + synchronized (smsLock) { + waitingForSms = value; + } + } + + public static void showKeyboard(View view) { + if (view == null) { + return; + } + InputMethodManager inputManager = (InputMethodManager)view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); + inputManager.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT); + + ((InputMethodManager) view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE)).showSoftInput(view, 0); + } + + public static boolean isKeyboardShowed(View view) { + if (view == null) { + return false; + } + InputMethodManager inputManager = (InputMethodManager) view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); + return inputManager.isActive(view); + } + + public static void hideKeyboard(View view) { + if (view == null) { + return; + } + InputMethodManager imm = (InputMethodManager) view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); + if (!imm.isActive()) { + return; + } + imm.hideSoftInputFromWindow(view.getWindowToken(), 0); + } + + public static File getCacheDir() { + if (externalCacheNotAvailableState == 1 || externalCacheNotAvailableState == 0 && Environment.getExternalStorageState().startsWith(Environment.MEDIA_MOUNTED)) { + externalCacheNotAvailableState = 1; + File file = ApplicationLoader.applicationContext.getExternalCacheDir(); + if (file != null) { + return file; + } + } + externalCacheNotAvailableState = 2; + File file = ApplicationLoader.applicationContext.getCacheDir(); + if (file != null) { + return file; + } + return new File(""); + } + + public static int dp(int value) { + return (int)(Math.max(1, density * value)); + } + + public static int dpf(float value) { + return (int)Math.ceil(density * value); + } + + public static void checkDisplaySize() { + try { + WindowManager manager = (WindowManager)ApplicationLoader.applicationContext.getSystemService(Context.WINDOW_SERVICE); + if (manager != null) { + Display display = manager.getDefaultDisplay(); + if (display != null) { + if(android.os.Build.VERSION.SDK_INT < 13) { + displaySize.set(display.getWidth(), display.getHeight()); + } else { + display.getSize(displaySize); + } + FileLog.e("tmessages", "display size = " + displaySize.x + " " + displaySize.y); + } + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/AppStartReceiver.java b/TMessagesProj/src/main/java/org/telegram/android/AppStartReceiver.java similarity index 90% rename from TMessagesProj/src/main/java/org/telegram/messenger/AppStartReceiver.java rename to TMessagesProj/src/main/java/org/telegram/android/AppStartReceiver.java index d1048d029..aa630862f 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/AppStartReceiver.java +++ b/TMessagesProj/src/main/java/org/telegram/android/AppStartReceiver.java @@ -6,12 +6,13 @@ * Copyright Nikolai Kudashov, 2013-2014. */ -package org.telegram.messenger; +package org.telegram.android; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; +import org.telegram.messenger.Utilities; import org.telegram.ui.ApplicationLoader; public class AppStartReceiver extends BroadcastReceiver { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/AuthenticatorService.java b/TMessagesProj/src/main/java/org/telegram/android/AuthenticatorService.java similarity index 98% rename from TMessagesProj/src/main/java/org/telegram/messenger/AuthenticatorService.java rename to TMessagesProj/src/main/java/org/telegram/android/AuthenticatorService.java index e88d46ed2..1d9c4bdcc 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/AuthenticatorService.java +++ b/TMessagesProj/src/main/java/org/telegram/android/AuthenticatorService.java @@ -6,7 +6,7 @@ * Copyright Nikolai Kudashov, 2013. */ -package org.telegram.messenger; +package org.telegram.android; import android.accounts.AbstractAccountAuthenticator; import android.accounts.Account; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ContactsController.java b/TMessagesProj/src/main/java/org/telegram/android/ContactsController.java similarity index 98% rename from TMessagesProj/src/main/java/org/telegram/messenger/ContactsController.java rename to TMessagesProj/src/main/java/org/telegram/android/ContactsController.java index f270ab3b5..33d2b4bf1 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ContactsController.java +++ b/TMessagesProj/src/main/java/org/telegram/android/ContactsController.java @@ -6,7 +6,7 @@ * Copyright Nikolai Kudashov, 2013. */ -package org.telegram.messenger; +package org.telegram.android; import android.accounts.Account; import android.accounts.AccountManager; @@ -20,6 +20,16 @@ import android.provider.ContactsContract; import android.util.SparseArray; import org.telegram.PhoneFormat.PhoneFormat; +import org.telegram.messenger.BuildVars; +import org.telegram.messenger.ConnectionsManager; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.R; +import org.telegram.messenger.RPCRequest; +import org.telegram.messenger.TLObject; +import org.telegram.messenger.TLRPC; +import org.telegram.messenger.UserConfig; +import org.telegram.messenger.Utilities; import org.telegram.ui.ApplicationLoader; import java.util.ArrayList; @@ -151,6 +161,18 @@ public class ContactsController { } } + public void deleteAllAppAccounts() { + try { + AccountManager am = AccountManager.get(ApplicationLoader.applicationContext); + Account[] accounts = am.getAccountsByType("org.telegram.account"); + for (Account c : accounts) { + am.removeAccount(c, null, null); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + public void checkContacts() { Utilities.globalQueue.postRunnable(new Runnable() { @Override @@ -720,7 +742,7 @@ public class ContactsController { }); } } - }, null, true, RPCRequest.RPCRequestClassGeneric | RPCRequest.RPCRequestClassFailOnServerErrors | RPCRequest.RPCRequestClassCanCompress); + }, true, RPCRequest.RPCRequestClassGeneric | RPCRequest.RPCRequestClassFailOnServerErrors | RPCRequest.RPCRequestClassCanCompress); } } else { Utilities.stageQueue.postRunnable(new Runnable() { @@ -815,7 +837,7 @@ public class ContactsController { processLoadedContacts(res.contacts, res.users, 0); } } - }, null, true, RPCRequest.RPCRequestClassGeneric); + }, true, RPCRequest.RPCRequestClassGeneric); } } @@ -1540,7 +1562,7 @@ public class ContactsController { } }); } - }, null, true, RPCRequest.RPCRequestClassGeneric | RPCRequest.RPCRequestClassFailOnServerErrors | RPCRequest.RPCRequestClassCanCompress); + }, true, RPCRequest.RPCRequestClassGeneric | RPCRequest.RPCRequestClassFailOnServerErrors | RPCRequest.RPCRequestClassCanCompress); } public void deleteContact(final ArrayList users) { @@ -1607,6 +1629,6 @@ public class ContactsController { } }); } - }, null, true, RPCRequest.RPCRequestClassGeneric); + }, true, RPCRequest.RPCRequestClassGeneric); } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ContactsSyncAdapterService.java b/TMessagesProj/src/main/java/org/telegram/android/ContactsSyncAdapterService.java similarity index 96% rename from TMessagesProj/src/main/java/org/telegram/messenger/ContactsSyncAdapterService.java rename to TMessagesProj/src/main/java/org/telegram/android/ContactsSyncAdapterService.java index d6d3ecd32..852a84838 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ContactsSyncAdapterService.java +++ b/TMessagesProj/src/main/java/org/telegram/android/ContactsSyncAdapterService.java @@ -6,7 +6,7 @@ * Copyright Nikolai Kudashov, 2013. */ -package org.telegram.messenger; +package org.telegram.android; import android.accounts.Account; import android.accounts.OperationCanceledException; @@ -19,6 +19,8 @@ import android.content.SyncResult; import android.os.Bundle; import android.os.IBinder; +import org.telegram.messenger.FileLog; + public class ContactsSyncAdapterService extends Service { private static SyncAdapterImpl sSyncAdapter = null; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/Emoji.java b/TMessagesProj/src/main/java/org/telegram/android/Emoji.java similarity index 97% rename from TMessagesProj/src/main/java/org/telegram/messenger/Emoji.java rename to TMessagesProj/src/main/java/org/telegram/android/Emoji.java index 5bd32559d..3e7b108e2 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/Emoji.java +++ b/TMessagesProj/src/main/java/org/telegram/android/Emoji.java @@ -6,7 +6,7 @@ * Copyright Nikolai Kudashov, 2013. */ -package org.telegram.messenger; +package org.telegram.android; import java.io.File; import java.io.InputStream; @@ -26,6 +26,9 @@ import android.view.View; import android.view.ViewGroup; import android.widget.TextView; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.Utilities; import org.telegram.ui.ApplicationLoader; public class Emoji { @@ -202,17 +205,17 @@ public class Emoji { 0x00000000D83DDD34L, 0x00000000D83DDD35L, 0x00000000D83DDD3BL, 0x00000000D83DDD36L, 0x00000000D83DDD37L, 0x00000000D83DDD38L, 0x00000000D83DDD39L}}; static { - if (Utilities.density <= 1.0f) { + if (AndroidUtilities.density <= 1.0f) { emojiFullSize = 30; - } else if (Utilities.density <= 1.5f) { + } else if (AndroidUtilities.density <= 1.5f) { emojiFullSize = 45; - } else if (Utilities.density <= 2.0f) { + } else if (AndroidUtilities.density <= 2.0f) { emojiFullSize = 60; } else { emojiFullSize = 90; } - drawImgSize = Utilities.dp(20); - bigImgSize = Utilities.dp(30); + drawImgSize = AndroidUtilities.dp(20); + bigImgSize = AndroidUtilities.dp(30); for (int j = 1; j < data.length; j++) { for (int i = 0; i < data[j].length; i++) { @@ -228,13 +231,13 @@ public class Emoji { try { float scale = 1.0f; int imageResize = 1; - if (Utilities.density <= 1.0f) { + if (AndroidUtilities.density <= 1.0f) { scale = 2.0f; imageResize = 2; - } else if (Utilities.density <= 1.5f) { + } else if (AndroidUtilities.density <= 1.5f) { scale = 3.0f; imageResize = 2; - } else if (Utilities.density <= 2.0f) { + } else if (AndroidUtilities.density <= 2.0f) { scale = 2.0f; } else { scale = 3.0f; @@ -466,7 +469,7 @@ public class Emoji { public static class EmojiSpan extends ImageSpan { private Paint.FontMetricsInt fontMetrics = null; - int size = Utilities.dp(20); + int size = AndroidUtilities.dp(20); public EmojiSpan(Drawable d, int verticalAlignment, int s, Paint.FontMetricsInt original) { super(d, verticalAlignment); @@ -474,7 +477,7 @@ public class Emoji { if (original != null) { size = Math.abs(fontMetrics.descent) + Math.abs(fontMetrics.ascent); if (size == 0) { - size = Utilities.dp(20); + size = AndroidUtilities.dp(20); } } } @@ -488,8 +491,8 @@ public class Emoji { if (fontMetrics == null) { int sz = super.getSize(paint, text, start, end, fm); - int offset = Utilities.dp(8); - int w = Utilities.dp(10); + int offset = AndroidUtilities.dp(8); + int w = AndroidUtilities.dp(10); fm.top = -w - offset; fm.bottom = w - offset; fm.ascent = -w - offset; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/FastDateFormat.java b/TMessagesProj/src/main/java/org/telegram/android/FastDateFormat.java similarity index 99% rename from TMessagesProj/src/main/java/org/telegram/messenger/FastDateFormat.java rename to TMessagesProj/src/main/java/org/telegram/android/FastDateFormat.java index 91b7d0eb9..0d0a029ae 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/FastDateFormat.java +++ b/TMessagesProj/src/main/java/org/telegram/android/FastDateFormat.java @@ -5,7 +5,7 @@ * * Copyright Nikolai Kudashov, 2013. */ -package org.telegram.messenger; +package org.telegram.android; import java.io.IOException; import java.io.ObjectInputStream; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/GcmBroadcastReceiver.java b/TMessagesProj/src/main/java/org/telegram/android/GcmBroadcastReceiver.java similarity index 95% rename from TMessagesProj/src/main/java/org/telegram/messenger/GcmBroadcastReceiver.java rename to TMessagesProj/src/main/java/org/telegram/android/GcmBroadcastReceiver.java index 763265830..291717aeb 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/GcmBroadcastReceiver.java +++ b/TMessagesProj/src/main/java/org/telegram/android/GcmBroadcastReceiver.java @@ -6,7 +6,7 @@ * Copyright Nikolai Kudashov, 2013. */ -package org.telegram.messenger; +package org.telegram.android; import android.app.Activity; import android.content.BroadcastReceiver; @@ -14,6 +14,9 @@ import android.content.Context; import android.content.Intent; import org.json.JSONObject; +import org.telegram.messenger.ConnectionsManager; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.Utilities; import org.telegram.ui.ApplicationLoader; public class GcmBroadcastReceiver extends BroadcastReceiver { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java b/TMessagesProj/src/main/java/org/telegram/android/LocaleController.java similarity index 95% rename from TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java rename to TMessagesProj/src/main/java/org/telegram/android/LocaleController.java index 3b80c2a19..852e64355 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java +++ b/TMessagesProj/src/main/java/org/telegram/android/LocaleController.java @@ -6,7 +6,7 @@ * Copyright Nikolai Kudashov, 2013-2014. */ -package org.telegram.messenger; +package org.telegram.android; import android.app.Activity; import android.content.BroadcastReceiver; @@ -18,6 +18,11 @@ import android.content.res.Configuration; import android.text.format.DateFormat; import android.util.Xml; +import org.telegram.messenger.ConnectionsManager; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.R; +import org.telegram.messenger.TLRPC; +import org.telegram.messenger.Utilities; import org.telegram.ui.ApplicationLoader; import org.xmlpull.v1.XmlPullParser; @@ -215,6 +220,9 @@ public class LocaleController { if (currentInfo == null && systemDefaultLocale.getLanguage() != null) { currentInfo = languagesDict.get(systemDefaultLocale.getLanguage()); } + if (currentInfo == null) { + currentInfo = languagesDict.get(getLocaleString(systemDefaultLocale)); + } if (currentInfo == null) { currentInfo = languagesDict.get("en"); } @@ -231,6 +239,29 @@ public class LocaleController { } } + private String getLocaleString(Locale locale) { + if (locale == null) { + return ""; + } + String languageCode = locale.getLanguage(); + String countryCode = locale.getCountry(); + String variantCode = locale.getVariant(); + if (languageCode.length() == 0 && countryCode.length() == 0) { + return ""; + } + StringBuilder result = new StringBuilder(11); + result.append(languageCode); + if (countryCode.length() > 0 || variantCode.length() > 0) { + result.append('_'); + } + result.append(countryCode); + if (variantCode.length() > 0) { + result.append('_'); + } + result.append(variantCode); + return result.toString(); + } + public boolean applyLanguageFile(File file) { try { HashMap stringMap = getLocaleFileStrings(file); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java b/TMessagesProj/src/main/java/org/telegram/android/MediaController.java similarity index 98% rename from TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java rename to TMessagesProj/src/main/java/org/telegram/android/MediaController.java index edd741ede..da29c291c 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java +++ b/TMessagesProj/src/main/java/org/telegram/android/MediaController.java @@ -6,7 +6,7 @@ * Copyright Nikolai Kudashov, 2013-2014. */ -package org.telegram.messenger; +package org.telegram.android; import android.app.ProgressDialog; import android.content.Context; @@ -26,6 +26,15 @@ import android.os.Vibrator; import android.provider.MediaStore; import android.view.View; +import org.telegram.messenger.ConnectionsManager; +import org.telegram.messenger.DispatchQueue; +import org.telegram.messenger.FileLoader; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.R; +import org.telegram.messenger.TLRPC; +import org.telegram.messenger.UserConfig; +import org.telegram.messenger.Utilities; import org.telegram.objects.MessageObject; import org.telegram.ui.ApplicationLoader; import org.telegram.ui.Cells.ChatMediaCell; @@ -129,6 +138,7 @@ public class MediaController implements NotificationCenter.NotificationCenterDel public final static int recordStopped = 50006; public final static int screenshotTook = 50007; public final static int albumsDidLoaded = 50008; + public final static int audioDidSent = 50009; private HashMap>> loadingFileObservers = new HashMap>>(); private HashMap observersByTag = new HashMap(); @@ -497,7 +507,7 @@ public class MediaController implements NotificationCenter.NotificationCenterDel Thread.sleep(1000); } if (bitmapRegionDecoder != null) { - Bitmap bitmap = bitmapRegionDecoder.decodeRegion(new Rect(0, 0, Utilities.dp(44), Utilities.dp(44)), null); + Bitmap bitmap = bitmapRegionDecoder.decodeRegion(new Rect(0, 0, AndroidUtilities.dp(44), AndroidUtilities.dp(44)), null); int w = bitmap.getWidth(); int h = bitmap.getHeight(); for (int y = 0; y < h; y++) { @@ -926,7 +936,7 @@ public class MediaController implements NotificationCenter.NotificationCenterDel return true; } clenupPlayer(true); - final File cacheFile = new File(Utilities.getCacheDir(), messageObject.getFileName()); + final File cacheFile = new File(AndroidUtilities.getCacheDir(), messageObject.getFileName()); if (isOpusFile(cacheFile.getAbsolutePath()) == 1) { synchronized (playerObjectSync) { @@ -1144,10 +1154,11 @@ public class MediaController implements NotificationCenter.NotificationCenterDel recordingAudio.dc_id = Integer.MIN_VALUE; recordingAudio.id = UserConfig.lastLocalId; recordingAudio.user_id = UserConfig.getClientUserId(); + recordingAudio.mime_type = "audio/ogg"; UserConfig.lastLocalId--; UserConfig.saveConfig(false); - recordingAudioFile = new File(Utilities.getCacheDir(), MessageObject.getAttachFileName(recordingAudio)); + recordingAudioFile = new File(AndroidUtilities.getCacheDir(), MessageObject.getAttachFileName(recordingAudio)); try { if (startRecord(recordingAudioFile.getAbsolutePath()) == 0) { @@ -1257,6 +1268,7 @@ public class MediaController implements NotificationCenter.NotificationCenterDel } else { recordingAudioFileToSend.delete(); } + NotificationCenter.getInstance().postNotificationName(audioDidSent); } }); } @@ -1292,7 +1304,6 @@ public class MediaController implements NotificationCenter.NotificationCenterDel if (audioRecorder == null) { return; } - //recordTimeCount = System.currentTimeMillis() - recordStartTime; try { sendAfterDone = send; audioRecorder.stop(); @@ -1334,7 +1345,7 @@ public class MediaController implements NotificationCenter.NotificationCenterDel } } if (file == null) { - file = new File(Utilities.getCacheDir(), path); + file = new File(AndroidUtilities.getCacheDir(), path); } final File sourceFile = file; @@ -1466,7 +1477,7 @@ public class MediaController implements NotificationCenter.NotificationCenterDel } } if (cacheFile == null) { - cacheFile = new File(Utilities.getCacheDir(), messageObject.getFileName()); + cacheFile = new File(AndroidUtilities.getCacheDir(), messageObject.getFileName()); } try { currentGifDrawable = new GifDrawable(cacheFile); @@ -1545,7 +1556,7 @@ public class MediaController implements NotificationCenter.NotificationCenterDel UserConfig.lastLocalId--; parcelFD = ApplicationLoader.applicationContext.getContentResolver().openFileDescriptor(uri, "r"); input = new FileInputStream(parcelFD.getFileDescriptor()); - File f = new File(Utilities.getCacheDir(), String.format(Locale.US, "%d.%s", id, ext)); + File f = new File(AndroidUtilities.getCacheDir(), String.format(Locale.US, "%d.%s", id, ext)); output = new FileOutputStream(f); input.getChannel().transferTo(0, input.getChannel().size(), output.getChannel()); UserConfig.saveConfig(false); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java b/TMessagesProj/src/main/java/org/telegram/android/MessagesController.java similarity index 87% rename from TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java rename to TMessagesProj/src/main/java/org/telegram/android/MessagesController.java index 0522800fb..e514dc6cf 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java +++ b/TMessagesProj/src/main/java/org/telegram/android/MessagesController.java @@ -6,10 +6,8 @@ * Copyright Nikolai Kudashov, 2013. */ -package org.telegram.messenger; +package org.telegram.android; -import android.accounts.Account; -import android.accounts.AccountManager; import android.app.Activity; import android.app.AlertDialog; import android.app.Notification; @@ -23,21 +21,33 @@ import android.content.SharedPreferences; import android.content.pm.PackageInfo; import android.graphics.Bitmap; import android.media.AudioManager; -import android.media.SoundPool; import android.net.Uri; import android.os.Build; -import android.os.Vibrator; import android.provider.Settings; import android.support.v4.app.NotificationCompat; import android.text.Html; -import android.util.SparseArray; import org.json.JSONArray; import org.json.JSONObject; +import org.telegram.messenger.BuffersStorage; +import org.telegram.messenger.ByteBufferDesc; +import org.telegram.messenger.ConnectionsManager; +import org.telegram.messenger.FileLoader; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.MessageKeyData; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.R; +import org.telegram.messenger.RPCRequest; +import org.telegram.messenger.TLClassStore; +import org.telegram.messenger.TLObject; +import org.telegram.messenger.TLRPC; +import org.telegram.messenger.UserConfig; +import org.telegram.messenger.Utilities; import org.telegram.objects.MessageObject; import org.telegram.objects.PhotoObject; -import org.telegram.ui.LaunchActivity; import org.telegram.ui.ApplicationLoader; +import org.telegram.ui.LaunchActivity; +import org.telegram.ui.PopupNotificationActivity; import java.io.File; import java.math.BigInteger; @@ -56,15 +66,15 @@ public class MessagesController implements NotificationCenter.NotificationCenter public ArrayList dialogs = new ArrayList(); public ArrayList dialogsServerOnly = new ArrayList(); public ConcurrentHashMap dialogs_dict = new ConcurrentHashMap(100, 1.0f, 2); - public SparseArray dialogMessage = new SparseArray(); + public HashMap dialogMessage = new HashMap(); public ConcurrentHashMap> printingUsers = new ConcurrentHashMap>(100, 1.0f, 2); public HashMap printingStrings = new HashMap(); private int lastPrintingStringCount = 0; private HashMap> delayedMessages = new HashMap>(); - public SparseArray sendingMessages = new SparseArray(); - public SparseArray hidenAddToContacts = new SparseArray(); - private SparseArray acceptingChats = new SparseArray(); + public HashMap sendingMessages = new HashMap(); + public HashMap hidenAddToContacts = new HashMap(); + private HashMap acceptingChats = new HashMap(); private ArrayList updatesQueue = new ArrayList(); private ArrayList pendingEncMessagesToDelete = new ArrayList(); private long updatesStartWaitTime = 0; @@ -84,18 +94,18 @@ public class MessagesController implements NotificationCenter.NotificationCenter public boolean updatingState = false; public boolean firstGettingTask = false; public boolean registeringForPush = false; - private long lastSoundPlay = 0; + private long lastStatusUpdateTime = 0; private long statusRequest = 0; private int statusSettingState = 0; private boolean offlineSent = false; private String uploadingAvatar = null; - private SoundPool soundPool; - private int sound; + public boolean enableJoined = true; - public int fontSize = Utilities.dp(16); + public int fontSize = AndroidUtilities.dp(16); public MessageObject currentPushMessage; + public ArrayList pushMessages = new ArrayList(); private class UserActionUpdates extends TLRPC.Updates { @@ -168,6 +178,9 @@ public class MessagesController implements NotificationCenter.NotificationCenter public static final int removeAllMessagesFromDialog = 25; + public static final int notificationsSettingsUpdated = 26; + public static final int pushMessagesUpdated = 27; + private static volatile MessagesController Instance = null; public static MessagesController getInstance() { MessagesController localInstance = Instance; @@ -192,13 +205,6 @@ public class MessagesController implements NotificationCenter.NotificationCenter enableJoined = preferences.getBoolean("EnableContactJoined", true); preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); fontSize = preferences.getInt("fons_size", 16); - - try { - soundPool = new SoundPool(1, AudioManager.STREAM_NOTIFICATION, 0); - sound = soundPool.load(ApplicationLoader.applicationContext, R.raw.sound_a, 1); - } catch (Exception e) { - FileLog.e("tmessages", e); - } } public void addSupportUser() { @@ -233,9 +239,136 @@ public class MessagesController implements NotificationCenter.NotificationCenter @Override public void didReceivedNotification(int id, Object... args) { if (id == FileLoader.FileDidUpload) { - fileDidUploaded((String)args[0], (TLRPC.InputFile)args[1], (TLRPC.InputEncryptedFile)args[2]); + final String location = (String)args[0]; + final TLRPC.InputFile file = (TLRPC.InputFile)args[1]; + final TLRPC.InputEncryptedFile encryptedFile = (TLRPC.InputEncryptedFile)args[2]; + + if (uploadingAvatar != null && uploadingAvatar.equals(location)) { + TLRPC.TL_photos_uploadProfilePhoto req = new TLRPC.TL_photos_uploadProfilePhoto(); + req.caption = ""; + req.crop = new TLRPC.TL_inputPhotoCropAuto(); + req.file = file; + req.geo_point = new TLRPC.TL_inputGeoPointEmpty(); + ConnectionsManager.getInstance().performRpc(req, new RPCRequest.RPCRequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + if (error == null) { + TLRPC.User user = users.get(UserConfig.getClientUserId()); + if (user == null) { + user = UserConfig.getCurrentUser(); + users.put(user.id, user); + } else { + UserConfig.setCurrentUser(user); + } + if (user == null) { + return; + } + TLRPC.TL_photos_photo photo = (TLRPC.TL_photos_photo) response; + ArrayList sizes = photo.photo.sizes; + TLRPC.PhotoSize smallSize = PhotoObject.getClosestPhotoSizeWithSize(sizes, 100, 100); + TLRPC.PhotoSize bigSize = PhotoObject.getClosestPhotoSizeWithSize(sizes, 1000, 1000); + user.photo = new TLRPC.TL_userProfilePhoto(); + user.photo.photo_id = photo.photo.id; + if (smallSize != null) { + user.photo.photo_small = smallSize.location; + } + if (bigSize != null) { + user.photo.photo_big = bigSize.location; + } else if (smallSize != null) { + user.photo.photo_small = smallSize.location; + } + MessagesStorage.getInstance().clearUserPhotos(user.id); + ArrayList users = new ArrayList(); + users.add(user); + MessagesStorage.getInstance().putUsersAndChats(users, null, false, true); + Utilities.RunOnUIThread(new Runnable() { + @Override + public void run() { + NotificationCenter.getInstance().postNotificationName(updateInterfaces, UPDATE_MASK_AVATAR); + UserConfig.saveConfig(true); + } + }); + } + } + }); + } else { + Utilities.RunOnUIThread(new Runnable() { + @Override + public void run() { + ArrayList arr = delayedMessages.get(location); + if (arr != null) { + for (int a = 0; a < arr.size(); a++) { + DelayedMessage message = arr.get(a); + if (file != null && message.sendRequest != null) { + if (message.type == 0) { + message.sendRequest.media.file = file; + performSendMessageRequest(message.sendRequest, message.obj, message.originalPath); + } else if (message.type == 1) { + if (message.sendRequest.media.thumb == null) { + message.sendRequest.media.thumb = file; + performSendDelayedMessage(message); + } else { + message.sendRequest.media.file = file; + performSendMessageRequest(message.sendRequest, message.obj, message.originalPath); + } + } else if (message.type == 2) { + if (message.sendRequest.media.thumb == null && message.location != null) { + message.sendRequest.media.thumb = file; + performSendDelayedMessage(message); + } else { + message.sendRequest.media.file = file; + performSendMessageRequest(message.sendRequest, message.obj, message.originalPath); + } + } else if (message.type == 3) { + message.sendRequest.media.file = file; + performSendMessageRequest(message.sendRequest, message.obj, message.originalPath); + } + arr.remove(a); + a--; + } else if (encryptedFile != null && message.sendEncryptedRequest != null) { + message.sendEncryptedRequest.media.key = encryptedFile.key; + message.sendEncryptedRequest.media.iv = encryptedFile.iv; + performSendEncryptedRequest(message.sendEncryptedRequest, message.obj, message.encryptedChat, encryptedFile, message.originalPath); + arr.remove(a); + a--; + } + } + if (arr.isEmpty()) { + delayedMessages.remove(location); + } + } + } + }); + } } else if (id == FileLoader.FileDidFailUpload) { - fileDidFailedUpload((String) args[0], (Boolean) args[1]); + final String location = (String) args[0]; + final boolean enc = (Boolean) args[1]; + + if (uploadingAvatar != null && uploadingAvatar.equals(location)) { + uploadingAvatar = null; + } else { + Utilities.RunOnUIThread(new Runnable() { + @Override + public void run() { + ArrayList arr = delayedMessages.get(location); + if (arr != null) { + for (int a = 0; a < arr.size(); a++) { + DelayedMessage obj = arr.get(a); + if (enc && obj.sendEncryptedRequest != null || !enc && obj.sendRequest != null) { + obj.obj.messageOwner.send_state = MESSAGE_SEND_STATE_SEND_ERROR; + sendingMessages.remove(obj.obj.messageOwner.id); + arr.remove(a); + a--; + NotificationCenter.getInstance().postNotificationName(messageSendError, obj.obj.messageOwner.id); + } + } + if (arr.isEmpty()) { + delayedMessages.remove(location); + } + } + } + }); + } } else if (id == messageReceivedByServer) { Integer msgId = (Integer)args[0]; MessageObject obj = dialogMessage.get(msgId); @@ -315,6 +448,8 @@ public class MessagesController implements NotificationCenter.NotificationCenter startingSecretChat = false; statusRequest = 0; statusSettingState = 0; + currentPushMessage = null; + pushMessages.clear(); addSupportUser(); } @@ -382,18 +517,6 @@ public class MessagesController implements NotificationCenter.NotificationCenter }); } - public void deleteAllAppAccounts() { - try { - AccountManager am = AccountManager.get(ApplicationLoader.applicationContext); - Account[] accounts = am.getAccountsByType("org.telegram.account"); - for (Account c : accounts) { - am.removeAccount(c, null, null); - } - } catch (Exception e) { - e.printStackTrace(); - } - } - public void loadUserPhotos(final int uid, final int offset, final int count, final long max_id, final boolean fromCache, final int classGuid) { if (fromCache) { MessagesStorage.getInstance().getUserPhotos(uid, offset, count, max_id, classGuid); @@ -415,7 +538,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter processLoadedUserPhotos(res, uid, offset, count, max_id, fromCache, classGuid); } } - }, null, true, RPCRequest.RPCRequestClassGeneric); + }); ConnectionsManager.getInstance().bindRequestToGuid(reqId, classGuid); } } @@ -518,7 +641,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter processLoadedMedia(res, uid, offset, count, max_id, false, classGuid); } } - }, null, true, RPCRequest.RPCRequestClassGeneric); + }); ConnectionsManager.getInstance().bindRequestToGuid(reqId, classGuid); } } @@ -580,14 +703,14 @@ public class MessagesController implements NotificationCenter.NotificationCenter } } } - }, null, true, RPCRequest.RPCRequestClassGeneric); + }); ConnectionsManager.getInstance().bindRequestToGuid(reqId, classGuid); } } public void uploadAndApplyUserAvatar(TLRPC.PhotoSize bigPhoto) { if (bigPhoto != null) { - uploadingAvatar = Utilities.getCacheDir() + "/" + bigPhoto.location.volume_id + "_" + bigPhoto.location.local_id + ".jpg"; + uploadingAvatar = AndroidUtilities.getCacheDir() + "/" + bigPhoto.location.volume_id + "_" + bigPhoto.location.local_id + ".jpg"; FileLoader.getInstance().uploadFile(uploadingAvatar, false); } } @@ -623,7 +746,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter public void run(TLObject response, TLRPC.TL_error error) { } - }, null, true, RPCRequest.RPCRequestClassGeneric); + }); } public void deleteDialog(final long did, int offset, final boolean onlyHistory) { @@ -688,7 +811,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter } } } - }, null, true, RPCRequest.RPCRequestClassGeneric); + }); } else { int encId = (int)(did >> 32); if (onlyHistory) { @@ -734,7 +857,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter } }); } - }, null, true, RPCRequest.RPCRequestClassGeneric); + }); } else { Utilities.RunOnUIThread(new Runnable() { @Override @@ -761,7 +884,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter checkDeletingTask(); if (UserConfig.isClientActivated()) { - if (ConnectionsManager.lastPauseTime == 0) { + if (ConnectionsManager.getInstance().getPauseTime() == 0 && ApplicationLoader.isScreenOn) { if (statusSettingState != 1 && (lastStatusUpdateTime == 0 || lastStatusUpdateTime <= System.currentTimeMillis() - 55000 || offlineSent)) { statusSettingState = 1; @@ -785,9 +908,9 @@ public class MessagesController implements NotificationCenter.NotificationCenter } statusRequest = 0; } - }, null, true, RPCRequest.RPCRequestClassGeneric); + }); } - } else if (statusSettingState != 2 && !offlineSent && ConnectionsManager.lastPauseTime <= System.currentTimeMillis() - 2000) { + } else if (statusSettingState != 2 && !offlineSent && ConnectionsManager.getInstance().getPauseTime() <= System.currentTimeMillis() - 2000) { statusSettingState = 2; if (statusRequest != 0) { ConnectionsManager.getInstance().cancelRpc(statusRequest, true); @@ -806,7 +929,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter } statusRequest = 0; } - }, null, true, RPCRequest.RPCRequestClassGeneric); + }); } if (updatesStartWaitTime != 0 && updatesStartWaitTime + 1500 < currentTime) { @@ -927,7 +1050,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter public void run(TLObject response, TLRPC.TL_error error) { } - }, null, true, RPCRequest.RPCRequestClassGeneric); + }); ConnectionsManager.getInstance().bindRequestToGuid(reqId, classGuid); } else { int encId = (int)(dialog_id >> 32); @@ -943,7 +1066,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter public void run(TLObject response, TLRPC.TL_error error) { } - }, null, true, RPCRequest.RPCRequestClassGeneric); + }); ConnectionsManager.getInstance().bindRequestToGuid(reqId, classGuid); } } @@ -980,7 +1103,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter processLoadedMessages(res, dialog_id, offset, count, max_id, false, classGuid, 0, 0, 0, 0, false); } } - }, null, true, RPCRequest.RPCRequestClassGeneric); + }); ConnectionsManager.getInstance().bindRequestToGuid(reqId, classGuid); } } @@ -1062,7 +1185,29 @@ public class MessagesController implements NotificationCenter.NotificationCenter processLoadedDialogs(dialogsRes, null, offset, serverOffset, count, false, false); } } - }, null, true, RPCRequest.RPCRequestClassGeneric); + }); + } + } + + private void applyDialogsNotificationsSettings(ArrayList dialogs) { + SharedPreferences.Editor editor = null; + for (TLRPC.TL_dialog dialog : dialogs) { + if (dialog.peer != null && dialog.notify_settings instanceof TLRPC.TL_peerNotifySettings) { + if (editor == null) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE); + editor = preferences.edit(); + } + int dialog_id = dialog.peer.user_id; + if (dialog_id == 0) { + dialog_id = -dialog.peer.chat_id; + } + if (dialog.notify_settings.mute_until != 0) { + editor.putInt("notify2_" + dialog_id, 2); + } + } + } + if (editor != null) { + editor.commit(); } } @@ -1255,6 +1400,9 @@ public class MessagesController implements NotificationCenter.NotificationCenter Utilities.RunOnUIThread(new Runnable() { @Override public void run() { + if (!isCache) { + applyDialogsNotificationsSettings(dialogsRes.dialogs); + } for (TLRPC.User u : dialogsRes.users) { if (isCache) { if (u.id == UserConfig.getClientUserId() || u.id / 1000 == 333) { @@ -1360,10 +1508,8 @@ public class MessagesController implements NotificationCenter.NotificationCenter size.type = "x"; sizes.add(size); } - if (Build.VERSION.SDK_INT < 11) { - if (bitmap != null) { - bitmap.recycle(); - } + if (bitmap != null) { + bitmap.recycle(); } if (sizes.isEmpty()) { return null; @@ -1436,7 +1582,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter } } } - }, null, true, RPCRequest.RPCRequestClassGeneric); + }); } MessagesStorage.getInstance().storageQueue.postRunnable(new Runnable() { @@ -1464,7 +1610,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter public void run(TLObject response, TLRPC.TL_error error) { } - }, null, true, RPCRequest.RPCRequestClassGeneric | RPCRequest.RPCRequestClassFailOnServerErrors); + }, true, RPCRequest.RPCRequestClassGeneric | RPCRequest.RPCRequestClassFailOnServerErrors); } } else { if (max_date == 0) { @@ -1484,7 +1630,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter public void run(TLObject response, TLRPC.TL_error error) { //MessagesStorage.getInstance().processPendingRead(dialog_id, max_id, max_date, true); } - }, null, true, RPCRequest.RPCRequestClassGeneric); + }); } MessagesStorage.getInstance().processPendingRead(dialog_id, max_id, max_date, false); @@ -1732,7 +1878,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter type = 2; newMsg.message = "-1"; TLRPC.FileLocation location1 = photo.sizes.get(photo.sizes.size() - 1).location; - newMsg.attachPath = Utilities.getCacheDir() + "/" + location1.volume_id + "_" + location1.local_id + ".jpg"; + newMsg.attachPath = AndroidUtilities.getCacheDir() + "/" + location1.volume_id + "_" + location1.local_id + ".jpg"; } else if (video != null) { newMsg = new TLRPC.TL_message(); newMsg.media = new TLRPC.TL_messageMediaVideo(); @@ -1896,6 +2042,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter reqSend.media.duration = video.duration; reqSend.media.w = video.w; reqSend.media.h = video.h; + reqSend.media.mime_type = video.mime_type; DelayedMessage delayedMessage = new DelayedMessage(); delayedMessage.originalPath = originalPath; delayedMessage.sendRequest = reqSend; @@ -1946,6 +2093,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter } else if (type == 8) { reqSend.media = new TLRPC.TL_inputMediaUploadedAudio(); reqSend.media.duration = audio.duration; + reqSend.media.mime_type = audio.mime_type; DelayedMessage delayedMessage = new DelayedMessage(); delayedMessage.sendRequest = reqSend; delayedMessage.type = 3; @@ -1992,7 +2140,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter performSendEncryptedRequest(reqSend, newMsgObj, encryptedChat, encryptedFile, null); } } else if (type == 3) { - reqSend.media = new TLRPC.TL_decryptedMessageMediaVideo(); + reqSend.media = new TLRPC.TL_decryptedMessageMediaVideo_old(); reqSend.media.duration = video.duration; reqSend.media.size = video.size; reqSend.media.w = video.w; @@ -2000,6 +2148,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter reqSend.media.thumb = video.thumb.bytes; reqSend.media.thumb_h = video.thumb.h; reqSend.media.thumb_w = video.thumb.w; + reqSend.media.mime_type = "video/mp4"; if (video.access_hash == 0) { DelayedMessage delayedMessage = new DelayedMessage(); delayedMessage.originalPath = originalPath; @@ -2056,9 +2205,10 @@ public class MessagesController implements NotificationCenter.NotificationCenter performSendEncryptedRequest(reqSend, newMsgObj, encryptedChat, encryptedFile, null); } } else if (type == 8) { - reqSend.media = new TLRPC.TL_decryptedMessageMediaAudio(); + reqSend.media = new TLRPC.TL_decryptedMessageMediaAudio_old(); reqSend.media.duration = audio.duration; reqSend.media.size = audio.size; + reqSend.media.mime_type = "audio/ogg"; DelayedMessage delayedMessage = new DelayedMessage(); delayedMessage.sendEncryptedRequest = reqSend; @@ -2098,8 +2248,8 @@ public class MessagesController implements NotificationCenter.NotificationCenter if (fileName.equals(fileName2)) { break; } - File cacheFile = new File(Utilities.getCacheDir(), fileName + ".jpg"); - File cacheFile2 = new File(Utilities.getCacheDir(), fileName2 + ".jpg"); + File cacheFile = new File(AndroidUtilities.getCacheDir(), fileName + ".jpg"); + File cacheFile2 = new File(AndroidUtilities.getCacheDir(), fileName2 + ".jpg"); cacheFile.renameTo(cacheFile2); FileLoader.getInstance().replaceImageInCache(fileName, fileName2); size2.location = size.location; @@ -2118,8 +2268,8 @@ public class MessagesController implements NotificationCenter.NotificationCenter String fileName = size2.location.volume_id + "_" + size2.location.local_id; String fileName2 = size.location.volume_id + "_" + size.location.local_id; if (!fileName.equals(fileName2)) { - File cacheFile = new File(Utilities.getCacheDir(), fileName + ".jpg"); - File cacheFile2 = new File(Utilities.getCacheDir(), fileName2 + ".jpg"); + File cacheFile = new File(AndroidUtilities.getCacheDir(), fileName + ".jpg"); + File cacheFile2 = new File(AndroidUtilities.getCacheDir(), fileName2 + ".jpg"); boolean result = cacheFile.renameTo(cacheFile2); FileLoader.getInstance().replaceImageInCache(fileName, fileName2); size2.location = size.location; @@ -2136,16 +2286,16 @@ public class MessagesController implements NotificationCenter.NotificationCenter String fileName = size2.location.volume_id + "_" + size2.location.local_id; String fileName2 = size.location.volume_id + "_" + size.location.local_id; if (!fileName.equals(fileName2)) { - File cacheFile = new File(Utilities.getCacheDir(), fileName + ".jpg"); - File cacheFile2 = new File(Utilities.getCacheDir(), fileName2 + ".jpg"); + File cacheFile = new File(AndroidUtilities.getCacheDir(), fileName + ".jpg"); + File cacheFile2 = new File(AndroidUtilities.getCacheDir(), fileName2 + ".jpg"); boolean result = cacheFile.renameTo(cacheFile2); FileLoader.getInstance().replaceImageInCache(fileName, fileName2); size2.location = size.location; } } - if (newMsg.attachPath != null && newMsg.attachPath.startsWith(Utilities.getCacheDir().getAbsolutePath())) { + if (newMsg.attachPath != null && newMsg.attachPath.startsWith(AndroidUtilities.getCacheDir().getAbsolutePath())) { File cacheFile = new File(newMsg.attachPath); - File cacheFile2 = new File(Utilities.getCacheDir(), MessageObject.getAttachFileName(sentMessage.media.document)); + File cacheFile2 = new File(AndroidUtilities.getCacheDir(), MessageObject.getAttachFileName(sentMessage.media.document)); boolean result = cacheFile.renameTo(cacheFile2); if (result) { newMsg.attachPath = null; @@ -2166,8 +2316,8 @@ public class MessagesController implements NotificationCenter.NotificationCenter 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)) { - File cacheFile = new File(Utilities.getCacheDir(), fileName); - File cacheFile2 = new File(Utilities.getCacheDir(), fileName2); + File cacheFile = new File(AndroidUtilities.getCacheDir(), fileName); + File cacheFile2 = new File(AndroidUtilities.getCacheDir(), fileName2); cacheFile.renameTo(cacheFile2); newMsg.media.audio.dc_id = sentMessage.media.audio.dc_id; newMsg.media.audio.id = sentMessage.media.audio.id; @@ -2185,8 +2335,8 @@ public class MessagesController implements NotificationCenter.NotificationCenter size.location.secret = file.access_hash; size.location.local_id = file.key_fingerprint; String fileName2 = size.location.volume_id + "_" + size.location.local_id; - File cacheFile = new File(Utilities.getCacheDir(), fileName + ".jpg"); - File cacheFile2 = new File(Utilities.getCacheDir(), fileName2 + ".jpg"); + File cacheFile = new File(AndroidUtilities.getCacheDir(), fileName + ".jpg"); + File cacheFile2 = new File(AndroidUtilities.getCacheDir(), fileName2 + ".jpg"); boolean result = cacheFile.renameTo(cacheFile2); FileLoader.getInstance().replaceImageInCache(fileName, fileName2); ArrayList arr = new ArrayList(); @@ -2211,6 +2361,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter newMsg.media.video.key = decryptedMessage.media.key; newMsg.media.video.iv = decryptedMessage.media.iv; newMsg.media.video.path = video.path; + newMsg.media.video.mime_type = video.mime_type; ArrayList arr = new ArrayList(); arr.add(newMsg); MessagesStorage.getInstance().putMessages(arr, false, true); @@ -2232,9 +2383,9 @@ public class MessagesController implements NotificationCenter.NotificationCenter newMsg.media.document.thumb = document.thumb; newMsg.media.document.dc_id = file.dc_id; - if (document.path != null && document.path.startsWith(Utilities.getCacheDir().getAbsolutePath())) { + if (document.path != null && document.path.startsWith(AndroidUtilities.getCacheDir().getAbsolutePath())) { File cacheFile = new File(document.path); - File cacheFile2 = new File(Utilities.getCacheDir(), MessageObject.getAttachFileName(newMsg.media.document)); + File cacheFile2 = new File(AndroidUtilities.getCacheDir(), MessageObject.getAttachFileName(newMsg.media.document)); cacheFile.renameTo(cacheFile2); } @@ -2256,12 +2407,13 @@ public class MessagesController implements NotificationCenter.NotificationCenter newMsg.media.audio.key = decryptedMessage.media.key; newMsg.media.audio.iv = decryptedMessage.media.iv; newMsg.media.audio.path = audio.path; + newMsg.media.audio.mime_type = audio.mime_type; String fileName = audio.dc_id + "_" + audio.id + ".m4a"; String fileName2 = newMsg.media.audio.dc_id + "_" + newMsg.media.audio.id + ".m4a"; if (!fileName.equals(fileName2)) { - File cacheFile = new File(Utilities.getCacheDir(), fileName); - File cacheFile2 = new File(Utilities.getCacheDir(), fileName2); + File cacheFile = new File(AndroidUtilities.getCacheDir(), fileName); + File cacheFile2 = new File(AndroidUtilities.getCacheDir(), fileName2); cacheFile.renameTo(cacheFile2); } @@ -2276,44 +2428,44 @@ public class MessagesController implements NotificationCenter.NotificationCenter if (req == null || chat.auth_key == null || chat instanceof TLRPC.TL_encryptedChatRequested || chat instanceof TLRPC.TL_encryptedChatWaiting) { return; } - //TLRPC.decryptedMessageLayer messageLayer = new TLRPC.decryptedMessageLayer(); - //messageLayer.layer = 8; - //messageLayer.message = req; - SerializedData data = new SerializedData(); - req.serializeToStream(data); + int len = req.getObjectSize(); + ByteBufferDesc toEncrypt = BuffersStorage.getInstance().getFreeBuffer(4 + len); + toEncrypt.writeInt32(len); + req.serializeToStream(toEncrypt); - SerializedData toEncrypt = new SerializedData(); - toEncrypt.writeInt32(data.length()); - toEncrypt.writeRaw(data.toByteArray()); - - byte[] innerData = toEncrypt.toByteArray(); - - byte[] messageKeyFull = Utilities.computeSHA1(innerData); + byte[] messageKeyFull = Utilities.computeSHA1(toEncrypt.buffer); byte[] messageKey = new byte[16]; System.arraycopy(messageKeyFull, messageKeyFull.length - 16, messageKey, 0, 16); MessageKeyData keyData = Utilities.generateMessageKeyData(chat.auth_key, messageKey, false); - SerializedData dataForEncryption = new SerializedData(); - dataForEncryption.writeRaw(innerData); - byte[] b = new byte[1]; - while (dataForEncryption.length() % 16 != 0) { + len = toEncrypt.length(); + int extraLen = len % 16 != 0 ? 16 - len % 16 : 0; + ByteBufferDesc dataForEncryption = BuffersStorage.getInstance().getFreeBuffer(len + extraLen); + toEncrypt.position(0); + dataForEncryption.writeRaw(toEncrypt); + if (extraLen != 0) { + byte[] b = new byte[extraLen]; Utilities.random.nextBytes(b); - dataForEncryption.writeByte(b[0]); + dataForEncryption.writeRaw(b); } + BuffersStorage.getInstance().reuseFreeBuffer(toEncrypt); - byte[] encryptedData = Utilities.aesIgeEncryption(dataForEncryption.toByteArray(), keyData.aesKey, keyData.aesIv, true, false, 0); + Utilities.aesIgeEncryption(dataForEncryption.buffer, keyData.aesKey, keyData.aesIv, true, false, 0, dataForEncryption.limit()); - data = new SerializedData(); + ByteBufferDesc data = BuffersStorage.getInstance().getFreeBuffer(8 + messageKey.length + dataForEncryption.length()); + dataForEncryption.position(0); data.writeInt64(chat.key_fingerprint); data.writeRaw(messageKey); - data.writeRaw(encryptedData); + data.writeRaw(dataForEncryption); + BuffersStorage.getInstance().reuseFreeBuffer(dataForEncryption); + data.position(0); - TLObject reqToSend; + TLObject reqToSend = null; if (encryptedFile == null) { TLRPC.TL_messages_sendEncrypted req2 = new TLRPC.TL_messages_sendEncrypted(); - req2.data = data.toByteArray(); + req2.data = data; req2.random_id = req.random_id; req2.peer = new TLRPC.TL_inputEncryptedChat(); req2.peer.chat_id = chat.id; @@ -2321,7 +2473,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter reqToSend = req2; } else { TLRPC.TL_messages_sendEncryptedFile req2 = new TLRPC.TL_messages_sendEncryptedFile(); - req2.data = data.toByteArray(); + req2.data = data; req2.random_id = req.random_id; req2.peer = new TLRPC.TL_inputEncryptedChat(); req2.peer.chat_id = chat.id; @@ -2365,7 +2517,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter } } } - }, null, true, RPCRequest.RPCRequestClassGeneric | RPCRequest.RPCRequestClassCanCompress); + }); } private void performSendMessageRequest(TLObject req, final MessageObject newMsgObj, final String originalPath) { @@ -2477,7 +2629,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter }); } } - }, null, (req instanceof TLRPC.TL_messages_forwardMessages ? null : new RPCRequest.RPCQuickAckDelegate() { + }, (req instanceof TLRPC.TL_messages_forwardMessages ? null : new RPCRequest.RPCQuickAckDelegate() { @Override public void quickAck() { final int msg_id = newMsgObj.messageOwner.id; @@ -2503,7 +2655,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter private void performSendDelayedMessage(final DelayedMessage message) { if (message.type == 0) { - String location = Utilities.getCacheDir() + "/" + message.location.volume_id + "_" + message.location.local_id + ".jpg"; + String location = AndroidUtilities.getCacheDir() + "/" + message.location.volume_id + "_" + message.location.local_id + ".jpg"; putToDelayedMessages(location, message); if (message.sendRequest != null) { FileLoader.getInstance().uploadFile(location, false); @@ -2513,13 +2665,13 @@ public class MessagesController implements NotificationCenter.NotificationCenter } else if (message.type == 1) { if (message.sendRequest != null) { if (message.sendRequest.media.thumb == null) { - String location = Utilities.getCacheDir() + "/" + message.location.volume_id + "_" + message.location.local_id + ".jpg"; + String location = AndroidUtilities.getCacheDir() + "/" + message.location.volume_id + "_" + message.location.local_id + ".jpg"; putToDelayedMessages(location, message); FileLoader.getInstance().uploadFile(location, false); } else { String location = message.videoLocation.path; if (location == null) { - location = Utilities.getCacheDir() + "/" + message.videoLocation.id + ".mp4"; + location = AndroidUtilities.getCacheDir() + "/" + message.videoLocation.id + ".mp4"; } putToDelayedMessages(location, message); FileLoader.getInstance().uploadFile(location, false); @@ -2527,14 +2679,14 @@ public class MessagesController implements NotificationCenter.NotificationCenter } else { String location = message.videoLocation.path; if (location == null) { - location = Utilities.getCacheDir() + "/" + message.videoLocation.id + ".mp4"; + location = AndroidUtilities.getCacheDir() + "/" + message.videoLocation.id + ".mp4"; } putToDelayedMessages(location, message); FileLoader.getInstance().uploadFile(location, true); } } else if (message.type == 2) { if (message.sendRequest != null && message.sendRequest.media.thumb == null && message.location != null) { - String location = Utilities.getCacheDir() + "/" + message.location.volume_id + "_" + message.location.local_id + ".jpg"; + String location = AndroidUtilities.getCacheDir() + "/" + message.location.volume_id + "_" + message.location.local_id + ".jpg"; putToDelayedMessages(location, message); FileLoader.getInstance().uploadFile(location, false); } else { @@ -2557,134 +2709,6 @@ public class MessagesController implements NotificationCenter.NotificationCenter } } - public void fileDidFailedUpload(final String location, final boolean enc) { - if (uploadingAvatar != null && uploadingAvatar.equals(location)) { - uploadingAvatar = null; - } else { - Utilities.RunOnUIThread(new Runnable() { - @Override - public void run() { - ArrayList arr = delayedMessages.get(location); - if (arr != null) { - for (int a = 0; a < arr.size(); a++) { - DelayedMessage obj = arr.get(a); - if (enc && obj.sendEncryptedRequest != null || !enc && obj.sendRequest != null) { - obj.obj.messageOwner.send_state = MESSAGE_SEND_STATE_SEND_ERROR; - sendingMessages.remove(obj.obj.messageOwner.id); - arr.remove(a); - a--; - NotificationCenter.getInstance().postNotificationName(messageSendError, obj.obj.messageOwner.id); - } - } - if (arr.isEmpty()) { - delayedMessages.remove(location); - } - } - } - }); - } - } - - public void fileDidUploaded(final String location, final TLRPC.InputFile file, final TLRPC.InputEncryptedFile encryptedFile) { - if (uploadingAvatar != null && uploadingAvatar.equals(location)) { - TLRPC.TL_photos_uploadProfilePhoto req = new TLRPC.TL_photos_uploadProfilePhoto(); - req.caption = ""; - req.crop = new TLRPC.TL_inputPhotoCropAuto(); - req.file = file; - req.geo_point = new TLRPC.TL_inputGeoPointEmpty(); - ConnectionsManager.getInstance().performRpc(req, new RPCRequest.RPCRequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - if (error == null) { - TLRPC.User user = users.get(UserConfig.getClientUserId()); - if (user == null) { - user = UserConfig.getCurrentUser(); - users.put(user.id, user); - } else { - UserConfig.setCurrentUser(user); - } - if (user == null) { - return; - } - TLRPC.TL_photos_photo photo = (TLRPC.TL_photos_photo) response; - ArrayList sizes = photo.photo.sizes; - TLRPC.PhotoSize smallSize = PhotoObject.getClosestPhotoSizeWithSize(sizes, 100, 100); - TLRPC.PhotoSize bigSize = PhotoObject.getClosestPhotoSizeWithSize(sizes, 1000, 1000); - user.photo = new TLRPC.TL_userProfilePhoto(); - user.photo.photo_id = photo.photo.id; - if (smallSize != null) { - user.photo.photo_small = smallSize.location; - } - if (bigSize != null) { - user.photo.photo_big = bigSize.location; - } else if (smallSize != null) { - user.photo.photo_small = smallSize.location; - } - MessagesStorage.getInstance().clearUserPhotos(user.id); - ArrayList users = new ArrayList(); - users.add(user); - MessagesStorage.getInstance().putUsersAndChats(users, null, false, true); - Utilities.RunOnUIThread(new Runnable() { - @Override - public void run() { - NotificationCenter.getInstance().postNotificationName(updateInterfaces, UPDATE_MASK_AVATAR); - UserConfig.saveConfig(true); - } - }); - } - } - }, null, true, RPCRequest.RPCRequestClassGeneric); - } else { - Utilities.RunOnUIThread(new Runnable() { - @Override - public void run() { - ArrayList arr = delayedMessages.get(location); - if (arr != null) { - for (int a = 0; a < arr.size(); a++) { - DelayedMessage message = arr.get(a); - if (file != null && message.sendRequest != null) { - if (message.type == 0) { - message.sendRequest.media.file = file; - performSendMessageRequest(message.sendRequest, message.obj, message.originalPath); - } else if (message.type == 1) { - if (message.sendRequest.media.thumb == null) { - message.sendRequest.media.thumb = file; - performSendDelayedMessage(message); - } else { - message.sendRequest.media.file = file; - performSendMessageRequest(message.sendRequest, message.obj, message.originalPath); - } - } else if (message.type == 2) { - if (message.sendRequest.media.thumb == null && message.location != null) { - message.sendRequest.media.thumb = file; - performSendDelayedMessage(message); - } else { - message.sendRequest.media.file = file; - performSendMessageRequest(message.sendRequest, message.obj, message.originalPath); - } - } else if (message.type == 3) { - message.sendRequest.media.file = file; - performSendMessageRequest(message.sendRequest, message.obj, message.originalPath); - } - arr.remove(a); - a--; - } else if (encryptedFile != null && message.sendEncryptedRequest != null) { - message.sendEncryptedRequest.media.key = encryptedFile.key; - message.sendEncryptedRequest.media.iv = encryptedFile.iv; - performSendEncryptedRequest(message.sendEncryptedRequest, message.obj, message.encryptedChat, encryptedFile, message.originalPath); - arr.remove(a); - a--; - } - } - if (arr.isEmpty()) { - delayedMessages.remove(location); - } - } - } - }); - } - } - public long createChat(String title, ArrayList selectedContacts, final TLRPC.InputFile uploadedAvatar) { TLRPC.TL_messages_createChat req = new TLRPC.TL_messages_createChat(); req.title = title; @@ -2756,7 +2780,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter } } } - }, null, true, RPCRequest.RPCRequestClassGeneric); + }); } public void addUserToChat(int chat_id, final TLRPC.User user, final TLRPC.ChatParticipants info) { @@ -2838,7 +2862,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter } } } - }, null, true, RPCRequest.RPCRequestClassGeneric); + }); } public void deleteUserFromChat(int chat_id, final TLRPC.User user, final TLRPC.ChatParticipants info) { @@ -2920,7 +2944,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter } } } - }, null, true, RPCRequest.RPCRequestClassGeneric); + }); } public void changeChatTitle(int chat_id, String title) { @@ -2980,7 +3004,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter } } } - }, null, true, RPCRequest.RPCRequestClassGeneric); + }); } public void changeChatAvatar(int chat_id, TLRPC.InputFile uploadedAvatar) { @@ -3046,7 +3070,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter } } } - }, null, true, RPCRequest.RPCRequestClassGeneric); + }); } public void unregistedPush() { @@ -3059,7 +3083,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter public void run(TLObject response, TLRPC.TL_error error) { } - }, null, true, RPCRequest.RPCRequestClassGeneric); + }); } } @@ -3070,7 +3094,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter public void run(TLObject response, TLRPC.TL_error error) { ConnectionsManager.getInstance().cleanUp(); } - }, null, true, RPCRequest.RPCRequestClassGeneric); + }); } public void registerForPush(final String regid) { @@ -3136,7 +3160,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter } }); } - }, null, true, RPCRequest.RPCRequestClassGeneric); + }); } } @@ -3163,7 +3187,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter } } } - }, null, true, RPCRequest.RPCRequestClassGeneric); + }); } private int getUpdateSeq(TLRPC.Updates updates) { @@ -3221,7 +3245,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter FileLog.e("tmessages", "UPDATES QUEUE PROCEED - OK"); updatesStartWaitTime = 0; if (getDifference) { - final int stateCopy = ConnectionsManager.getInstance().connectionState; + final int stateCopy = ConnectionsManager.getInstance().getConnectionState(); Utilities.RunOnUIThread(new Runnable() { @Override public void run() { @@ -3231,7 +3255,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter } } else { if (getDifference) { - final int stateCopy = ConnectionsManager.getInstance().connectionState; + final int stateCopy = ConnectionsManager.getInstance().getConnectionState(); Utilities.RunOnUIThread(new Runnable() { @Override public void run() { @@ -3263,9 +3287,9 @@ public class MessagesController implements NotificationCenter.NotificationCenter req.date = MessagesStorage.lastDateValue; req.qts = MessagesStorage.lastQtsValue; FileLog.e("tmessages", "start getDifference with date = " + MessagesStorage.lastDateValue + " pts = " + MessagesStorage.lastPtsValue + " seq = " + MessagesStorage.lastSeqValue); - if (ConnectionsManager.getInstance().connectionState == 0) { - ConnectionsManager.getInstance().connectionState = 3; - final int stateCopy = ConnectionsManager.getInstance().connectionState; + if (ConnectionsManager.getInstance().getConnectionState() == 0) { + ConnectionsManager.getInstance().setConnectionState(3); + final int stateCopy = ConnectionsManager.getInstance().getConnectionState(); Utilities.RunOnUIThread(new Runnable() { @Override public void run() { @@ -3315,9 +3339,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter } if (currentPushMessage != null && readMessages.contains(currentPushMessage.messageOwner.id)) { - NotificationManager mNotificationManager = (NotificationManager) ApplicationLoader.applicationContext.getSystemService(Context.NOTIFICATION_SERVICE); - mNotificationManager.cancel(1); - currentPushMessage = null; + dismissNotification(); } } }); @@ -3375,7 +3397,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter } if (!(res instanceof TLRPC.TL_updates_differenceSlice)) { - if ((dialog_id != openned_dialog_id || ConnectionsManager.lastPauseTime != 0) && !obj.isOut() && obj.messageOwner.unread && (lastMessage == null || lastMessage.messageOwner.date < obj.messageOwner.date)) { + if ((dialog_id != openned_dialog_id || ConnectionsManager.getInstance().getPauseTime() != 0) && !obj.isOut() && obj.messageOwner.unread && (lastMessage == null || lastMessage.messageOwner.date < obj.messageOwner.date)) { if (!readMessages.contains(obj.messageOwner.id)) { lastMessage = obj; } @@ -3440,7 +3462,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter MessagesStorage.lastDateValue = res.state.date; MessagesStorage.lastPtsValue = res.state.pts; MessagesStorage.lastQtsValue = res.state.qts; - ConnectionsManager.getInstance().connectionState = 0; + ConnectionsManager.getInstance().setConnectionState(0); processUpdatesQueue(true); } else if (res instanceof TLRPC.TL_updates_differenceSlice) { MessagesStorage.lastDateValue = res.intermediate_state.date; @@ -3451,7 +3473,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter } else if (res instanceof TLRPC.TL_updates_differenceEmpty) { MessagesStorage.lastSeqValue = res.seq; MessagesStorage.lastDateValue = res.date; - ConnectionsManager.getInstance().connectionState = 0; + ConnectionsManager.getInstance().setConnectionState(0); processUpdatesQueue(true); } MessagesStorage.getInstance().saveDiffParams(MessagesStorage.lastSeqValue, MessagesStorage.lastPtsValue, MessagesStorage.lastDateValue, MessagesStorage.lastQtsValue); @@ -3463,8 +3485,8 @@ public class MessagesController implements NotificationCenter.NotificationCenter }); } else { gettingDifference = false; - ConnectionsManager.getInstance().connectionState = 0; - final int stateCopy = ConnectionsManager.getInstance().connectionState; + ConnectionsManager.getInstance().setConnectionState(0); + final int stateCopy = ConnectionsManager.getInstance().getConnectionState(); Utilities.RunOnUIThread(new Runnable() { @Override public void run() { @@ -3473,7 +3495,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter }); } } - }, null, true, RPCRequest.RPCRequestClassGeneric); + }); } public void processUpdates(final TLRPC.Updates updates, boolean fromQueue) { @@ -3523,7 +3545,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter } else { dialog_id = obj.messageOwner.to_id.user_id; } - if (dialog_id != openned_dialog_id || ConnectionsManager.lastPauseTime != 0 || !ApplicationLoader.isScreenOn) { + if (dialog_id != openned_dialog_id || ConnectionsManager.getInstance().getPauseTime() != 0 || !ApplicationLoader.isScreenOn) { showInAppNotification(obj); } } @@ -3586,7 +3608,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter } else { dialog_id = obj.messageOwner.to_id.user_id; } - if (dialog_id != openned_dialog_id || ConnectionsManager.lastPauseTime != 0 || !ApplicationLoader.isScreenOn) { + if (dialog_id != openned_dialog_id || ConnectionsManager.getInstance().getPauseTime() != 0 || !ApplicationLoader.isScreenOn) { showInAppNotification(obj); } } @@ -3690,7 +3712,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter public void run(TLObject response, TLRPC.TL_error error) { } - }, null, true, RPCRequest.RPCRequestClassGeneric); + }); } MessagesStorage.getInstance().saveDiffParams(MessagesStorage.lastSeqValue, MessagesStorage.lastPtsValue, MessagesStorage.lastDateValue, MessagesStorage.lastQtsValue); } @@ -3790,12 +3812,10 @@ public class MessagesController implements NotificationCenter.NotificationCenter arr.add(obj); MessagesStorage.lastPtsValue = update.pts; if (upd.message.from_id != UserConfig.getClientUserId() && upd.message.to_id != null) { - if (uid != openned_dialog_id || ConnectionsManager.lastPauseTime != 0) { + if (uid != openned_dialog_id || ConnectionsManager.getInstance().getPauseTime() != 0) { lastMessage = obj; } } - } else if (update instanceof TLRPC.TL_updateMessageID) { - //can't be here } else if (update instanceof TLRPC.TL_updateReadMessages) { markAsReadMessages.addAll(update.messages); MessagesStorage.lastPtsValue = update.pts; @@ -3843,37 +3863,6 @@ public class MessagesController implements NotificationCenter.NotificationCenter } else if (update instanceof TLRPC.TL_updateUserPhoto) { interfaceUpdateMask |= UPDATE_MASK_AVATAR; MessagesStorage.getInstance().clearUserPhotos(update.user_id); - /*if (!(update.photo instanceof TLRPC.TL_userProfilePhotoEmpty)) { DEPRECATED - if (usersDict.containsKey(update.user_id)) { - TLRPC.TL_messageService newMessage = new TLRPC.TL_messageService(); - newMessage.action = new TLRPC.TL_messageActionUserUpdatedPhoto(); - newMessage.action.newUserPhoto = update.photo; - newMessage.local_id = newMessage.id = UserConfig.getNewMessageId(); - UserConfig.saveConfig(false); - newMessage.unread = true; - newMessage.date = update.date; - newMessage.from_id = update.user_id; - newMessage.to_id = new TLRPC.TL_peerUser(); - newMessage.to_id.user_id = UserConfig.clientUserId; - newMessage.out = false; - newMessage.dialog_id = update.user_id; - - messagesArr.add(newMessage); - MessageObject obj = new MessageObject(newMessage, usersDict); - ArrayList arr = messages.get(newMessage.dialog_id); - if (arr == null) { - arr = new ArrayList(); - messages.put(newMessage.dialog_id, arr); - } - arr.add(obj); - if (newMessage.from_id != UserConfig.clientUserId && newMessage.to_id != null) { - if (newMessage.dialog_id != openned_dialog_id || ApplicationLoader.lastPauseTime != 0) { - lastMessage = obj; - } - } - } - }*/ - updatesOnMainThread.add(update); } else if (update instanceof TLRPC.TL_updateContactRegistered) { if (enableJoined && usersDict.containsKey(update.user_id)) { @@ -3898,7 +3887,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter } arr.add(obj); if (newMessage.from_id != UserConfig.getClientUserId() && newMessage.to_id != null) { - if (newMessage.dialog_id != openned_dialog_id || ConnectionsManager.lastPauseTime != 0) { + if (newMessage.dialog_id != openned_dialog_id || ConnectionsManager.getInstance().getPauseTime() != 0) { lastMessage = obj; } } @@ -3947,7 +3936,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter } arr.add(obj); if (newMessage.from_id != UserConfig.getClientUserId() && newMessage.to_id != null) { - if (newMessage.dialog_id != openned_dialog_id || ConnectionsManager.lastPauseTime != 0) { + if (newMessage.dialog_id != openned_dialog_id || ConnectionsManager.getInstance().getPauseTime() != 0) { lastMessage = obj; } } @@ -3968,7 +3957,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter } arr.add(obj); if (message.from_id != UserConfig.getClientUserId() && message.to_id != null) { - if (uid != openned_dialog_id || ConnectionsManager.lastPauseTime != 0) { + if (uid != openned_dialog_id || ConnectionsManager.getInstance().getPauseTime() != 0) { lastMessage = obj; } } @@ -4082,6 +4071,10 @@ public class MessagesController implements NotificationCenter.NotificationCenter } }); } + } else if (update instanceof TLRPC.TL_updateUserBlocked) { + //TODO + } else if (update instanceof TLRPC.TL_updateNotifySettings) { + updatesOnMainThread.add(update); } } if (!messages.isEmpty()) { @@ -4122,6 +4115,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter if (!updatesOnMainThread.isEmpty()) { ArrayList dbUsers = new ArrayList(); ArrayList dbUsersStatus = new ArrayList(); + SharedPreferences.Editor editor = null; for (TLRPC.Update update : updatesOnMainThread) { TLRPC.User toDbUser = new TLRPC.User(); toDbUser.id = update.user_id; @@ -4148,8 +4142,42 @@ public class MessagesController implements NotificationCenter.NotificationCenter avatarsUpdate = true; toDbUser.photo = update.photo; dbUsers.add(toDbUser); + } else if (update instanceof TLRPC.TL_updateNotifySettings) { + if (update.notify_settings instanceof TLRPC.TL_peerNotifySettings && update.peer instanceof TLRPC.TL_notifyPeer) { + if (editor == null) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE); + editor = preferences.edit(); + } + int dialog_id = update.peer.peer.user_id; + if (dialog_id == 0) { + dialog_id = -update.peer.peer.chat_id; + } + if (update.notify_settings.mute_until != 0) { + editor.putInt("notify2_" + dialog_id, 2); + } else { + editor.remove("notify2_" + dialog_id); + } + } else if (update.peer instanceof TLRPC.TL_notifyChats) { + if (editor == null) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE); + editor = preferences.edit(); + } + editor.putBoolean("EnableGroup", update.notify_settings.mute_until == 0); + editor.putBoolean("EnablePreviewGroup", update.notify_settings.show_previews); + } else if (update.peer instanceof TLRPC.TL_notifyUsers) { + if (editor == null) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE); + editor = preferences.edit(); + } + editor.putBoolean("EnableAll", update.notify_settings.mute_until == 0); + editor.putBoolean("EnablePreviewAll", update.notify_settings.show_previews); + } } } + if (editor != null) { + editor.commit(); + NotificationCenter.getInstance().postNotificationName(notificationsSettingsUpdated); + } MessagesStorage.getInstance().updateUsers(dbUsersStatus, true, true, true); MessagesStorage.getInstance().updateUsers(dbUsers, false, true, true); } @@ -4172,9 +4200,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter } if (currentPushMessage != null && markAsReadMessages.contains(currentPushMessage.messageOwner.id)) { - NotificationManager mNotificationManager = (NotificationManager)ApplicationLoader.applicationContext.getSystemService(Context.NOTIFICATION_SERVICE); - mNotificationManager.cancel(1); - currentPushMessage = null; + dismissNotification(); } } if (!markAsReadEncrypted.isEmpty()) { @@ -4297,324 +4323,6 @@ public class MessagesController implements NotificationCenter.NotificationCenter return false; } - private void playNotificationSound() { - if (lastSoundPlay > System.currentTimeMillis() - 1800) { - return; - } - try { - lastSoundPlay = System.currentTimeMillis(); - soundPool.play(sound, 1, 1, 1, 0, 1); - } catch (Exception e) { - FileLog.e("tmessages", e); - } - } - - private void showInAppNotification(MessageObject messageObject) { - if (!UserConfig.isClientActivated()) { - return; - } - if (ConnectionsManager.lastPauseTime != 0) { - ConnectionsManager.lastPauseTime = System.currentTimeMillis(); - FileLog.e("tmessages", "reset sleep timeout by received message"); - } - if (messageObject == null) { - return; - } - SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Context.MODE_PRIVATE); - boolean globalEnabled = preferences.getBoolean("EnableAll", true); - boolean groupEnabled = preferences.getBoolean("EnableGroup", true); - - long dialog_id = messageObject.messageOwner.dialog_id; - int chat_id = messageObject.messageOwner.to_id.chat_id; - int user_id = messageObject.messageOwner.to_id.user_id; - if (user_id == 0) { - user_id = messageObject.messageOwner.from_id; - } else if (user_id == UserConfig.getClientUserId()) { - user_id = messageObject.messageOwner.from_id; - } - - if (dialog_id == 0) { - if (chat_id != 0) { - dialog_id = -chat_id; - } else if (user_id != 0) { - dialog_id = user_id; - } - } - - int notify_override = preferences.getInt("notify2_" + dialog_id, 0); - if (notify_override == 2 || (!globalEnabled || chat_id != 0 && !groupEnabled) && notify_override == 0) { - return; - } - - TLRPC.User user = users.get(user_id); - if (user == null) { - return; - } - TLRPC.Chat chat = null; - if (chat_id != 0) { - chat = chats.get(chat_id); - if (chat == null) { - return; - } - } - - int vibrate_override = preferences.getInt("vibrate_" + dialog_id, 0); - - if (ConnectionsManager.lastPauseTime == 0 && ApplicationLoader.isScreenOn) { - boolean inAppSounds = preferences.getBoolean("EnableInAppSounds", true); - boolean inAppVibrate = preferences.getBoolean("EnableInAppVibrate", true); - boolean inAppPreview = preferences.getBoolean("EnableInAppPreview", true); - - if (inAppSounds || inAppVibrate || inAppPreview) { - if ((int)dialog_id == 0) { - TLRPC.EncryptedChat encChat = encryptedChats.get((int)(dialog_id >> 32)); - if (encChat == null) { - return; - } - } - - if (inAppPreview) { - NotificationCenter.getInstance().postNotificationName(701, messageObject); - } - if (inAppVibrate && vibrate_override == 0 || vibrate_override == 1) { - Vibrator v = (Vibrator)ApplicationLoader.applicationContext.getSystemService(Context.VIBRATOR_SERVICE); - v.vibrate(100); - } - if (inAppSounds) { - playNotificationSound(); - } - } - } else { - TLRPC.FileLocation photoPath = null; - String defaultPath = Settings.System.DEFAULT_NOTIFICATION_URI.getPath(); - - NotificationManager mNotificationManager = (NotificationManager)ApplicationLoader.applicationContext.getSystemService(Context.NOTIFICATION_SERVICE); - Intent intent = new Intent(ApplicationLoader.applicationContext, LaunchActivity.class); - String msg = null; - - if ((int)dialog_id != 0) { - if (chat_id != 0) { - intent.putExtra("chatId", chat_id); - } else if (user_id != 0) { - intent.putExtra("userId", user_id); - } - - if (user.photo != null && user.photo.photo_small != null && user.photo.photo_small.volume_id != 0 && user.photo.photo_small.local_id != 0) { - photoPath = user.photo.photo_small; - } - - if (chat_id == 0 && user_id != 0) { - if (preferences.getBoolean("EnablePreviewAll", true)) { - if (messageObject.messageOwner instanceof TLRPC.TL_messageService) { - if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionUserJoined) { - msg = LocaleController.formatString("NotificationContactJoined", R.string.NotificationContactJoined, Utilities.formatName(user.first_name, user.last_name)); - } else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionUserUpdatedPhoto) { - msg = LocaleController.formatString("NotificationContactNewPhoto", R.string.NotificationContactNewPhoto, Utilities.formatName(user.first_name, user.last_name)); - } else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionLoginUnknownLocation) { - String date = String.format("%s %s %s", LocaleController.formatterYear.format(((long)messageObject.messageOwner.date) * 1000), LocaleController.getString("OtherAt", R.string.OtherAt), LocaleController.formatterDay.format(((long)messageObject.messageOwner.date) * 1000)); - msg = LocaleController.formatString("NotificationUnrecognizedDevice", R.string.NotificationUnrecognizedDevice, UserConfig.getCurrentUser().first_name, date, messageObject.messageOwner.action.title, messageObject.messageOwner.action.address); - } - } else { - if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaEmpty) { - if (messageObject.messageOwner.message != null && messageObject.messageOwner.message.length() != 0) { - msg = LocaleController.formatString("NotificationMessageText", R.string.NotificationMessageText, Utilities.formatName(user.first_name, user.last_name), messageObject.messageOwner.message); - } else { - msg = LocaleController.formatString("NotificationMessageNoText", R.string.NotificationMessageNoText, Utilities.formatName(user.first_name, user.last_name)); - } - } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaPhoto) { - msg = LocaleController.formatString("NotificationMessagePhoto", R.string.NotificationMessagePhoto, Utilities.formatName(user.first_name, user.last_name)); - } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaVideo) { - msg = LocaleController.formatString("NotificationMessageVideo", R.string.NotificationMessageVideo, Utilities.formatName(user.first_name, user.last_name)); - } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaContact) { - msg = LocaleController.formatString("NotificationMessageContact", R.string.NotificationMessageContact, Utilities.formatName(user.first_name, user.last_name)); - } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaGeo) { - msg = LocaleController.formatString("NotificationMessageMap", R.string.NotificationMessageMap, Utilities.formatName(user.first_name, user.last_name)); - } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaDocument) { - msg = LocaleController.formatString("NotificationMessageDocument", R.string.NotificationMessageDocument, Utilities.formatName(user.first_name, user.last_name)); - } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaAudio) { - msg = LocaleController.formatString("NotificationMessageAudio", R.string.NotificationMessageAudio, Utilities.formatName(user.first_name, user.last_name)); - } - } - } else { - msg = LocaleController.formatString("NotificationMessageNoText", R.string.NotificationMessageNoText, Utilities.formatName(user.first_name, user.last_name)); - } - } else if (chat_id != 0) { - if (preferences.getBoolean("EnablePreviewGroup", true)) { - if (messageObject.messageOwner instanceof TLRPC.TL_messageService) { - if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionChatAddUser) { - if (messageObject.messageOwner.action.user_id == UserConfig.getClientUserId()) { - msg = LocaleController.formatString("NotificationInvitedToGroup", R.string.NotificationInvitedToGroup, Utilities.formatName(user.first_name, user.last_name), chat.title); - } else { - TLRPC.User u2 = users.get(messageObject.messageOwner.action.user_id); - if (u2 == null) { - return; - } - msg = LocaleController.formatString("NotificationGroupAddMember", R.string.NotificationGroupAddMember, Utilities.formatName(user.first_name, user.last_name), chat.title, Utilities.formatName(u2.first_name, u2.last_name)); - } - } else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionChatEditTitle) { - msg = LocaleController.formatString("NotificationEditedGroupName", R.string.NotificationEditedGroupName, Utilities.formatName(user.first_name, user.last_name), messageObject.messageOwner.action.title); - } else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionChatEditPhoto || messageObject.messageOwner.action instanceof TLRPC.TL_messageActionChatDeletePhoto) { - msg = LocaleController.formatString("NotificationEditedGroupPhoto", R.string.NotificationEditedGroupPhoto, Utilities.formatName(user.first_name, user.last_name), chat.title); - } else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionChatDeleteUser) { - if (messageObject.messageOwner.action.user_id == UserConfig.getClientUserId()) { - msg = LocaleController.formatString("NotificationGroupKickYou", R.string.NotificationGroupKickYou, Utilities.formatName(user.first_name, user.last_name), chat.title); - } else if (messageObject.messageOwner.action.user_id == user.id) { - msg = LocaleController.formatString("NotificationGroupLeftMember", R.string.NotificationGroupLeftMember, Utilities.formatName(user.first_name, user.last_name), chat.title); - } else { - TLRPC.User u2 = users.get(messageObject.messageOwner.action.user_id); - if (u2 == null) { - return; - } - msg = LocaleController.formatString("NotificationGroupKickMember", R.string.NotificationGroupKickMember, Utilities.formatName(user.first_name, user.last_name), chat.title, Utilities.formatName(u2.first_name, u2.last_name)); - } - } - } else { - if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaEmpty) { - if (messageObject.messageOwner.message != null && messageObject.messageOwner.message.length() != 0) { - msg = LocaleController.formatString("NotificationMessageGroupText", R.string.NotificationMessageGroupText, Utilities.formatName(user.first_name, user.last_name), chat.title, messageObject.messageOwner.message); - } else { - msg = LocaleController.formatString("NotificationMessageGroupNoText", R.string.NotificationMessageGroupNoText, Utilities.formatName(user.first_name, user.last_name), chat.title); - } - } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaPhoto) { - msg = LocaleController.formatString("NotificationMessageGroupPhoto", R.string.NotificationMessageGroupPhoto, Utilities.formatName(user.first_name, user.last_name), chat.title); - } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaVideo) { - msg = LocaleController.formatString("NotificationMessageGroupVideo", R.string.NotificationMessageGroupVideo, Utilities.formatName(user.first_name, user.last_name), chat.title); - } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaContact) { - msg = LocaleController.formatString("NotificationMessageGroupContact", R.string.NotificationMessageGroupContact, Utilities.formatName(user.first_name, user.last_name), chat.title); - } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaGeo) { - msg = LocaleController.formatString("NotificationMessageGroupMap", R.string.NotificationMessageGroupMap, Utilities.formatName(user.first_name, user.last_name), chat.title); - } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaDocument) { - msg = LocaleController.formatString("NotificationMessageGroupDocument", R.string.NotificationMessageGroupDocument, Utilities.formatName(user.first_name, user.last_name), chat.title); - } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaAudio) { - msg = LocaleController.formatString("NotificationMessageGroupAudio", R.string.NotificationMessageGroupAudio, Utilities.formatName(user.first_name, user.last_name), chat.title); - } - } - } else { - msg = LocaleController.formatString("NotificationMessageGroupNoText", R.string.NotificationMessageGroupNoText, Utilities.formatName(user.first_name, user.last_name), chat.title); - } - } - } else { - msg = LocaleController.getString("YouHaveNewMessage", R.string.YouHaveNewMessage); - int enc_id = (int)(dialog_id >> 32); - intent.putExtra("encId", enc_id); - } - if (msg == null) { - return; - } - - boolean needVibrate = false; - String choosenSoundPath = null; - int ledColor = 0xff00ff00; - - choosenSoundPath = preferences.getString("sound_path_" + dialog_id, null); - - if (chat_id != 0) { - if (choosenSoundPath != null && choosenSoundPath.equals(defaultPath)) { - choosenSoundPath = null; - } else if (choosenSoundPath == null) { - choosenSoundPath = preferences.getString("GroupSoundPath", defaultPath); - } - needVibrate = preferences.getBoolean("EnableVibrateGroup", true); - ledColor = preferences.getInt("GroupLed", 0xff00ff00); - } else if (user_id != 0) { - if (choosenSoundPath != null && choosenSoundPath.equals(defaultPath)) { - choosenSoundPath = null; - } else if (choosenSoundPath == null) { - choosenSoundPath = preferences.getString("GlobalSoundPath", defaultPath); - } - needVibrate = preferences.getBoolean("EnableVibrateAll", true); - ledColor = preferences.getInt("MessagesLed", 0xff00ff00); - } - if (preferences.contains("color_" + dialog_id)) { - ledColor = preferences.getInt("color_" + dialog_id, 0); - } - - if (!needVibrate && vibrate_override == 1) { - needVibrate = true; - } else if (needVibrate && vibrate_override == 2) { - needVibrate = false; - } - - String name = Utilities.formatName(user.first_name, user.last_name); - if ((int)dialog_id == 0) { - name = LocaleController.getString("AppName", R.string.AppName); - } - String msgShort = msg.replace(name + ": ", "").replace(name + " ", ""); - - intent.setAction("com.tmessages.openchat" + Math.random() + Integer.MAX_VALUE); - intent.setFlags(32768); - PendingIntent contentIntent = PendingIntent.getActivity(ApplicationLoader.applicationContext, 0, intent, PendingIntent.FLAG_ONE_SHOT); - - NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(ApplicationLoader.applicationContext) - .setContentTitle(name) - .setSmallIcon(R.drawable.notification) - .setStyle(new NotificationCompat.BigTextStyle().bigText(msgShort)) - .setContentText(msgShort) - .setAutoCancel(true) - .setTicker(msg); - - if (photoPath != null) { - Bitmap img = FileLoader.getInstance().getImageFromMemory(photoPath, null, null, "50_50", false); - if (img != null) { - mBuilder.setLargeIcon(img); - } - } - - if (choosenSoundPath != null && !choosenSoundPath.equals("NoSound")) { - if (choosenSoundPath.equals(defaultPath)) { - mBuilder.setSound(Settings.System.DEFAULT_NOTIFICATION_URI, AudioManager.STREAM_NOTIFICATION); - } else { - mBuilder.setSound(Uri.parse(choosenSoundPath), AudioManager.STREAM_NOTIFICATION); - } - } - - currentPushMessage = null; - mBuilder.setContentIntent(contentIntent); - mNotificationManager.cancel(1); - Notification notification = mBuilder.build(); - if (ledColor != 0) { - notification.ledARGB = ledColor; - } - notification.ledOnMS = 1000; - notification.ledOffMS = 1000; - if (needVibrate) { - notification.vibrate = new long[]{0, 100, 0, 100}; - } else { - notification.vibrate = new long[]{0, 0}; - } - notification.flags |= Notification.FLAG_SHOW_LIGHTS; - try { - mNotificationManager.notify(1, notification); - if (preferences.getBoolean("EnablePebbleNotifications", false)) { - sendAlertToPebble(msg); - } - currentPushMessage = messageObject; - } catch (Exception e) { - FileLog.e("tmessages", e); - } - } - } - - public void sendAlertToPebble(String message) { - try { - final Intent i = new Intent("com.getpebble.action.SEND_NOTIFICATION"); - - final HashMap data = new HashMap(); - data.put("title", LocaleController.getString("AppName", R.string.AppName)); - data.put("body", message); - final JSONObject jsonData = new JSONObject(data); - final String notificationData = new JSONArray().put(jsonData).toString(); - - i.putExtra("messageType", "PEBBLE_ALERT"); - i.putExtra("sender", LocaleController.formatString("AppName", R.string.AppName)); - i.putExtra("notificationData", notificationData); - - ApplicationLoader.applicationContext.sendBroadcast(i); - } catch (Exception e) { - FileLog.e("tmessages", e); - } - } - public void dialogsUnreadCountIncr(final HashMap values) { Utilities.RunOnUIThread(new Runnable() { @Override @@ -4716,18 +4424,19 @@ public class MessagesController implements NotificationCenter.NotificationCenter if (chat == null) { return null; } - SerializedData is = new SerializedData(message.bytes); + ByteBufferDesc is = BuffersStorage.getInstance().getFreeBuffer(message.bytes.length); + is.writeRaw(message.bytes); + is.position(0); long fingerprint = is.readInt64(); if (chat.key_fingerprint == fingerprint) { byte[] messageKey = is.readData(16); MessageKeyData keyData = Utilities.generateMessageKeyData(chat.auth_key, messageKey, false); - byte[] messageData = is.readData(message.bytes.length - 24); - messageData = Utilities.aesIgeEncryption(messageData, keyData.aesKey, keyData.aesIv, false, false, 0); + Utilities.aesIgeEncryption(is.buffer, keyData.aesKey, keyData.aesIv, false, false, 24, is.limit() - 24); - is = new SerializedData(messageData); int len = is.readInt32(); TLObject object = TLClassStore.Instance().TLdeserialize(is, is.readInt32()); + BuffersStorage.getInstance().reuseFreeBuffer(is); if (object != null) { int from_id = chat.admin_id; @@ -4825,6 +4534,10 @@ public class MessagesController implements NotificationCenter.NotificationCenter newMessage.media.video.access_hash = message.file.access_hash; newMessage.media.video.key = decryptedMessage.media.key; newMessage.media.video.iv = decryptedMessage.media.iv; + newMessage.media.video.mime_type = decryptedMessage.media.mime_type; + if (newMessage.media.video.mime_type == null) { + newMessage.media.video.mime_type = "video/mp4"; + } } else if (decryptedMessage.media instanceof TLRPC.TL_decryptedMessageMediaDocument) { if (decryptedMessage.media.key == null || decryptedMessage.media.key.length != 32 || decryptedMessage.media.iv == null || decryptedMessage.media.iv.length != 32) { return null; @@ -4867,6 +4580,10 @@ public class MessagesController implements NotificationCenter.NotificationCenter newMessage.media.audio.iv = decryptedMessage.media.iv; newMessage.media.audio.dc_id = message.file.dc_id; newMessage.media.audio.duration = decryptedMessage.media.duration; + newMessage.media.audio.mime_type = decryptedMessage.media.mime_type; + if (newMessage.media.audio.mime_type == null) { + newMessage.media.audio.mime_type = "audio/ogg"; + } } else { return null; } @@ -4925,6 +4642,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter } else { FileLog.e("tmessages", "fingerprint mismatch"); } + BuffersStorage.getInstance().reuseFreeBuffer(is); return null; } @@ -4991,7 +4709,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter public void run(TLObject response, TLRPC.TL_error error) { } - }, null, true, RPCRequest.RPCRequestClassGeneric); + }); } public void acceptSecretChat(final TLRPC.EncryptedChat encryptedChat) { @@ -5086,12 +4804,12 @@ public class MessagesController implements NotificationCenter.NotificationCenter }); } } - }, null, true, RPCRequest.RPCRequestClassGeneric); + }); } else { acceptingChats.remove(encryptedChat.id); } } - }, null, true, RPCRequest.RPCRequestClassGeneric); + }); } public void startSecretChat(final Context context, final TLRPC.User user) { @@ -5230,7 +4948,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter }); } } - }, null, true, RPCRequest.RPCRequestClassGeneric | RPCRequest.RPCRequestClassFailOnServerErrors); + }, true, RPCRequest.RPCRequestClassGeneric | RPCRequest.RPCRequestClassFailOnServerErrors); } else { delayedEncryptedChatUpdates.clear(); Utilities.RunOnUIThread(new Runnable() { @@ -5248,7 +4966,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter }); } } - }, null, true, RPCRequest.RPCRequestClassGeneric | RPCRequest.RPCRequestClassFailOnServerErrors); + }, true, RPCRequest.RPCRequestClassGeneric | RPCRequest.RPCRequestClassFailOnServerErrors); progressDialog.setButton(DialogInterface.BUTTON_NEGATIVE, LocaleController.getString("Cancel", R.string.Cancel), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { @@ -5262,4 +4980,323 @@ public class MessagesController implements NotificationCenter.NotificationCenter }); progressDialog.show(); } + + private void showInAppNotification(MessageObject messageObject) { + if (!UserConfig.isClientActivated()) { + return; + } + ConnectionsManager.getInstance().resumeNetworkMaybe(); + if (messageObject == null) { + return; + } + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Context.MODE_PRIVATE); + boolean globalEnabled = preferences.getBoolean("EnableAll", true); + boolean groupEnabled = preferences.getBoolean("EnableGroup", true); + + long dialog_id = messageObject.messageOwner.dialog_id; + int chat_id = messageObject.messageOwner.to_id.chat_id; + int user_id = messageObject.messageOwner.to_id.user_id; + if (user_id == 0) { + user_id = messageObject.messageOwner.from_id; + } else if (user_id == UserConfig.getClientUserId()) { + user_id = messageObject.messageOwner.from_id; + } + + if (dialog_id == 0) { + if (chat_id != 0) { + dialog_id = -chat_id; + } else if (user_id != 0) { + dialog_id = user_id; + } + } + + int notify_override = preferences.getInt("notify2_" + dialog_id, 0); + if (notify_override == 2 || (!globalEnabled || chat_id != 0 && !groupEnabled) && notify_override == 0) { + return; + } + + TLRPC.User user = MessagesController.getInstance().users.get(user_id); + if (user == null) { + return; + } + TLRPC.Chat chat = null; + if (chat_id != 0) { + chat = MessagesController.getInstance().chats.get(chat_id); + if (chat == null) { + return; + } + } + + int vibrate_override = preferences.getInt("vibrate_" + dialog_id, 0); + boolean inAppSounds = preferences.getBoolean("EnableInAppSounds", true); + boolean inAppVibrate = preferences.getBoolean("EnableInAppVibrate", true); + boolean inAppPreview = preferences.getBoolean("EnableInAppPreview", true); + + TLRPC.FileLocation photoPath = null; + String defaultPath = Settings.System.DEFAULT_NOTIFICATION_URI.getPath(); + + NotificationManager mNotificationManager = (NotificationManager)ApplicationLoader.applicationContext.getSystemService(Context.NOTIFICATION_SERVICE); + Intent intent = new Intent(ApplicationLoader.applicationContext, LaunchActivity.class); + String msg = null; + + if ((int)dialog_id != 0) { + if (chat_id != 0) { + intent.putExtra("chatId", chat_id); + } else if (user_id != 0) { + intent.putExtra("userId", user_id); + } + + if (user.photo != null && user.photo.photo_small != null && user.photo.photo_small.volume_id != 0 && user.photo.photo_small.local_id != 0) { + photoPath = user.photo.photo_small; + } + + if (chat_id == 0 && user_id != 0) { + if (preferences.getBoolean("EnablePreviewAll", true)) { + if (messageObject.messageOwner instanceof TLRPC.TL_messageService) { + if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionUserJoined) { + msg = LocaleController.formatString("NotificationContactJoined", R.string.NotificationContactJoined, Utilities.formatName(user.first_name, user.last_name)); + } else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionUserUpdatedPhoto) { + msg = LocaleController.formatString("NotificationContactNewPhoto", R.string.NotificationContactNewPhoto, Utilities.formatName(user.first_name, user.last_name)); + } else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionLoginUnknownLocation) { + String date = String.format("%s %s %s", LocaleController.formatterYear.format(((long)messageObject.messageOwner.date) * 1000), LocaleController.getString("OtherAt", R.string.OtherAt), LocaleController.formatterDay.format(((long)messageObject.messageOwner.date) * 1000)); + msg = LocaleController.formatString("NotificationUnrecognizedDevice", R.string.NotificationUnrecognizedDevice, UserConfig.getCurrentUser().first_name, date, messageObject.messageOwner.action.title, messageObject.messageOwner.action.address); + } + } else { + if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaEmpty) { + if (messageObject.messageOwner.message != null && messageObject.messageOwner.message.length() != 0) { + msg = LocaleController.formatString("NotificationMessageText", R.string.NotificationMessageText, Utilities.formatName(user.first_name, user.last_name), messageObject.messageOwner.message); + } else { + msg = LocaleController.formatString("NotificationMessageNoText", R.string.NotificationMessageNoText, Utilities.formatName(user.first_name, user.last_name)); + } + } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaPhoto) { + msg = LocaleController.formatString("NotificationMessagePhoto", R.string.NotificationMessagePhoto, Utilities.formatName(user.first_name, user.last_name)); + } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaVideo) { + msg = LocaleController.formatString("NotificationMessageVideo", R.string.NotificationMessageVideo, Utilities.formatName(user.first_name, user.last_name)); + } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaContact) { + msg = LocaleController.formatString("NotificationMessageContact", R.string.NotificationMessageContact, Utilities.formatName(user.first_name, user.last_name)); + } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaGeo) { + msg = LocaleController.formatString("NotificationMessageMap", R.string.NotificationMessageMap, Utilities.formatName(user.first_name, user.last_name)); + } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaDocument) { + msg = LocaleController.formatString("NotificationMessageDocument", R.string.NotificationMessageDocument, Utilities.formatName(user.first_name, user.last_name)); + } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaAudio) { + msg = LocaleController.formatString("NotificationMessageAudio", R.string.NotificationMessageAudio, Utilities.formatName(user.first_name, user.last_name)); + } + } + } else { + msg = LocaleController.formatString("NotificationMessageNoText", R.string.NotificationMessageNoText, Utilities.formatName(user.first_name, user.last_name)); + } + } else if (chat_id != 0) { + if (preferences.getBoolean("EnablePreviewGroup", true)) { + if (messageObject.messageOwner instanceof TLRPC.TL_messageService) { + if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionChatAddUser) { + if (messageObject.messageOwner.action.user_id == UserConfig.getClientUserId()) { + msg = LocaleController.formatString("NotificationInvitedToGroup", R.string.NotificationInvitedToGroup, Utilities.formatName(user.first_name, user.last_name), chat.title); + } else { + TLRPC.User u2 = MessagesController.getInstance().users.get(messageObject.messageOwner.action.user_id); + if (u2 == null) { + return; + } + msg = LocaleController.formatString("NotificationGroupAddMember", R.string.NotificationGroupAddMember, Utilities.formatName(user.first_name, user.last_name), chat.title, Utilities.formatName(u2.first_name, u2.last_name)); + } + } else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionChatEditTitle) { + msg = LocaleController.formatString("NotificationEditedGroupName", R.string.NotificationEditedGroupName, Utilities.formatName(user.first_name, user.last_name), messageObject.messageOwner.action.title); + } else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionChatEditPhoto || messageObject.messageOwner.action instanceof TLRPC.TL_messageActionChatDeletePhoto) { + msg = LocaleController.formatString("NotificationEditedGroupPhoto", R.string.NotificationEditedGroupPhoto, Utilities.formatName(user.first_name, user.last_name), chat.title); + } else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionChatDeleteUser) { + if (messageObject.messageOwner.action.user_id == UserConfig.getClientUserId()) { + msg = LocaleController.formatString("NotificationGroupKickYou", R.string.NotificationGroupKickYou, Utilities.formatName(user.first_name, user.last_name), chat.title); + } else if (messageObject.messageOwner.action.user_id == user.id) { + msg = LocaleController.formatString("NotificationGroupLeftMember", R.string.NotificationGroupLeftMember, Utilities.formatName(user.first_name, user.last_name), chat.title); + } else { + TLRPC.User u2 = MessagesController.getInstance().users.get(messageObject.messageOwner.action.user_id); + if (u2 == null) { + return; + } + msg = LocaleController.formatString("NotificationGroupKickMember", R.string.NotificationGroupKickMember, Utilities.formatName(user.first_name, user.last_name), chat.title, Utilities.formatName(u2.first_name, u2.last_name)); + } + } + } else { + if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaEmpty) { + if (messageObject.messageOwner.message != null && messageObject.messageOwner.message.length() != 0) { + msg = LocaleController.formatString("NotificationMessageGroupText", R.string.NotificationMessageGroupText, Utilities.formatName(user.first_name, user.last_name), chat.title, messageObject.messageOwner.message); + } else { + msg = LocaleController.formatString("NotificationMessageGroupNoText", R.string.NotificationMessageGroupNoText, Utilities.formatName(user.first_name, user.last_name), chat.title); + } + } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaPhoto) { + msg = LocaleController.formatString("NotificationMessageGroupPhoto", R.string.NotificationMessageGroupPhoto, Utilities.formatName(user.first_name, user.last_name), chat.title); + } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaVideo) { + msg = LocaleController.formatString("NotificationMessageGroupVideo", R.string.NotificationMessageGroupVideo, Utilities.formatName(user.first_name, user.last_name), chat.title); + } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaContact) { + msg = LocaleController.formatString("NotificationMessageGroupContact", R.string.NotificationMessageGroupContact, Utilities.formatName(user.first_name, user.last_name), chat.title); + } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaGeo) { + msg = LocaleController.formatString("NotificationMessageGroupMap", R.string.NotificationMessageGroupMap, Utilities.formatName(user.first_name, user.last_name), chat.title); + } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaDocument) { + msg = LocaleController.formatString("NotificationMessageGroupDocument", R.string.NotificationMessageGroupDocument, Utilities.formatName(user.first_name, user.last_name), chat.title); + } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaAudio) { + msg = LocaleController.formatString("NotificationMessageGroupAudio", R.string.NotificationMessageGroupAudio, Utilities.formatName(user.first_name, user.last_name), chat.title); + } + } + } else { + msg = LocaleController.formatString("NotificationMessageGroupNoText", R.string.NotificationMessageGroupNoText, Utilities.formatName(user.first_name, user.last_name), chat.title); + } + } + } else { + msg = LocaleController.getString("YouHaveNewMessage", R.string.YouHaveNewMessage); + intent.putExtra("encId", (int)(dialog_id >> 32)); + } + if (msg == null) { + return; + } + + boolean needVibrate = false; + String choosenSoundPath = null; + int ledColor = 0xff00ff00; + + choosenSoundPath = preferences.getString("sound_path_" + dialog_id, null); + + if (chat_id != 0) { + if (choosenSoundPath != null && choosenSoundPath.equals(defaultPath)) { + choosenSoundPath = null; + } else if (choosenSoundPath == null) { + choosenSoundPath = preferences.getString("GroupSoundPath", defaultPath); + } + needVibrate = preferences.getBoolean("EnableVibrateGroup", true); + ledColor = preferences.getInt("GroupLed", 0xff00ff00); + } else if (user_id != 0) { + if (choosenSoundPath != null && choosenSoundPath.equals(defaultPath)) { + choosenSoundPath = null; + } else if (choosenSoundPath == null) { + choosenSoundPath = preferences.getString("GlobalSoundPath", defaultPath); + } + needVibrate = preferences.getBoolean("EnableVibrateAll", true); + ledColor = preferences.getInt("MessagesLed", 0xff00ff00); + } + if (preferences.contains("color_" + dialog_id)) { + ledColor = preferences.getInt("color_" + dialog_id, 0); + } + + if (!needVibrate && vibrate_override == 1) { + needVibrate = true; + } else if (needVibrate && vibrate_override == 2) { + needVibrate = false; + } + + String name = Utilities.formatName(user.first_name, user.last_name); + if ((int)dialog_id == 0) { + name = LocaleController.getString("AppName", R.string.AppName); + } + String msgShort = msg.replace(name + ": ", "").replace(name + " ", ""); + + intent.setAction("com.tmessages.openchat" + Math.random() + Integer.MAX_VALUE); + intent.setFlags(32768); + PendingIntent contentIntent = PendingIntent.getActivity(ApplicationLoader.applicationContext, 0, intent, PendingIntent.FLAG_ONE_SHOT); + + if (!ApplicationLoader.mainInterfacePaused) { + if (!inAppSounds) { + choosenSoundPath = null; + } + if (!inAppVibrate) { + needVibrate = false; + } + } + + NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(ApplicationLoader.applicationContext) + .setContentTitle(name) + .setSmallIcon(R.drawable.notification) + .setStyle(new NotificationCompat.BigTextStyle().bigText(msgShort)) + .setContentText(msgShort) + .setAutoCancel(true); + + if (ApplicationLoader.mainInterfacePaused || inAppPreview) { + mBuilder.setTicker(msg); + } + + if (photoPath != null) { + Bitmap img = FileLoader.getInstance().getImageFromMemory(photoPath, null, null, "50_50", false); + if (img != null) { + mBuilder.setLargeIcon(img); + } + } + + if (choosenSoundPath != null && !choosenSoundPath.equals("NoSound")) { + if (choosenSoundPath.equals(defaultPath)) { + mBuilder.setSound(Settings.System.DEFAULT_NOTIFICATION_URI, AudioManager.STREAM_NOTIFICATION); + } else { + mBuilder.setSound(Uri.parse(choosenSoundPath), AudioManager.STREAM_NOTIFICATION); + } + } + + long pauseTime = ConnectionsManager.getInstance().getPauseTime(); + if (ApplicationLoader.mainInterfacePaused || !ApplicationLoader.isScreenOn) { + int popup = 0; + if (chat != null) { + popup = preferences.getInt("popupGroup", 0); + } else { + popup = preferences.getInt("popupAll", 0); + } + if (popup == 3 || popup == 1 && ApplicationLoader.isScreenOn || popup == 2 && !ApplicationLoader.isScreenOn) { + Intent popupIntent = new Intent(ApplicationLoader.applicationContext, PopupNotificationActivity.class); + popupIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_ANIMATION | Intent.FLAG_ACTIVITY_NO_USER_ACTION | Intent.FLAG_FROM_BACKGROUND); + ApplicationLoader.applicationContext.startActivity(popupIntent); + } + } + + currentPushMessage = null; + mBuilder.setContentIntent(contentIntent); + Notification notification = mBuilder.build(); + if (ledColor != 0) { + notification.ledARGB = ledColor; + } + notification.ledOnMS = 1000; + notification.ledOffMS = 1000; + if (needVibrate) { + notification.vibrate = new long[]{0, 100, 0, 100}; + } else { + notification.vibrate = new long[]{0, 0}; + } + notification.flags |= Notification.FLAG_SHOW_LIGHTS; + try { + mNotificationManager.notify(1, notification); + currentPushMessage = messageObject; + pushMessages.add(0, messageObject); + NotificationCenter.getInstance().postNotificationName(pushMessagesUpdated); + if (preferences.getBoolean("EnablePebbleNotifications", false)) { + sendAlertToPebble(msg); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + + public void dismissNotification() { + try { + NotificationManager mNotificationManager = (NotificationManager)ApplicationLoader.applicationContext.getSystemService(Context.NOTIFICATION_SERVICE); + mNotificationManager.cancel(1); + MessagesController.getInstance().currentPushMessage = null; + MessagesController.getInstance().pushMessages.clear(); + NotificationCenter.getInstance().postNotificationName(pushMessagesUpdated); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + + public void sendAlertToPebble(String message) { + try { + final Intent i = new Intent("com.getpebble.action.SEND_NOTIFICATION"); + + final HashMap data = new HashMap(); + data.put("title", LocaleController.getString("AppName", R.string.AppName)); + data.put("body", message); + final JSONObject jsonData = new JSONObject(data); + final String notificationData = new JSONArray().put(jsonData).toString(); + + i.putExtra("messageType", "PEBBLE_ALERT"); + i.putExtra("sender", LocaleController.formatString("AppName", R.string.AppName)); + i.putExtra("notificationData", notificationData); + + ApplicationLoader.applicationContext.sendBroadcast(i); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java b/TMessagesProj/src/main/java/org/telegram/android/MessagesStorage.java similarity index 89% rename from TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java rename to TMessagesProj/src/main/java/org/telegram/android/MessagesStorage.java index 1448f6ff1..ab10e432c 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java +++ b/TMessagesProj/src/main/java/org/telegram/android/MessagesStorage.java @@ -6,7 +6,7 @@ * Copyright Nikolai Kudashov, 2013. */ -package org.telegram.messenger; +package org.telegram.android; import android.text.Html; import android.util.SparseArray; @@ -15,6 +15,17 @@ import org.telegram.PhoneFormat.PhoneFormat; import org.telegram.SQLite.SQLiteCursor; import org.telegram.SQLite.SQLiteDatabase; import org.telegram.SQLite.SQLitePreparedStatement; +import org.telegram.messenger.BuffersStorage; +import org.telegram.messenger.ByteBufferDesc; +import org.telegram.messenger.ConnectionsManager; +import org.telegram.messenger.DispatchQueue; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.TLClassStore; +import org.telegram.messenger.TLObject; +import org.telegram.messenger.TLRPC; +import org.telegram.messenger.UserConfig; +import org.telegram.messenger.Utilities; import org.telegram.objects.MessageObject; import org.telegram.ui.ApplicationLoader; @@ -28,6 +39,7 @@ public class MessagesStorage { public DispatchQueue storageQueue = new DispatchQueue("storageQueue"); private SQLiteDatabase database; private File cacheFile; + private BuffersStorage buffersStorage = new BuffersStorage(false); public static int lastDateValue = 0; public static int lastPtsValue = 0; public static int lastQtsValue = 0; @@ -63,8 +75,6 @@ public class MessagesStorage { } public void openDatabase() { - NativeLoader.initNativeLibs(ApplicationLoader.applicationContext); - cacheFile = new File(ApplicationLoader.applicationContext.getFilesDir(), "cache4.db"); boolean createTable = false; @@ -216,13 +226,14 @@ public class MessagesStorage { SQLitePreparedStatement state = database.executeFast("UPDATE params SET lsv = ?, sg = ?, pbytes = ? WHERE id = 1"); state.bindInteger(1, lsv); state.bindInteger(2, sg); + ByteBufferDesc data = buffersStorage.getFreeBuffer(pbytes != null ? pbytes.length : 1); if (pbytes != null) { - state.bindByteArray(3, pbytes); - } else { - state.bindByteArray(3, new byte[1]); + data.writeRaw(pbytes); } + state.bindByteBuffer(3, data.buffer); state.step(); state.dispose(); + buffersStorage.reuseFreeBuffer(data); } catch (Exception e) { FileLog.e("tmessages", e); } @@ -261,18 +272,19 @@ public class MessagesStorage { @Override public void run() { try { + int num = 0; database.executeFast("DELETE FROM wallpapers WHERE 1").stepThis().dispose(); database.beginTransaction(); SQLitePreparedStatement state = database.executeFast("REPLACE INTO wallpapers VALUES(?, ?)"); - int num = 0; for (TLRPC.WallPaper wallPaper : wallPapers) { state.requery(); - SerializedData data = new SerializedData(); + ByteBufferDesc data = buffersStorage.getFreeBuffer(wallPaper.getObjectSize()); wallPaper.serializeToStream(data); state.bindInteger(1, num); - state.bindByteArray(2, data.toByteArray()); + state.bindByteBuffer(2, data.buffer); state.step(); num++; + buffersStorage.reuseFreeBuffer(data); } state.dispose(); database.commitTransaction(); @@ -291,12 +303,12 @@ public class MessagesStorage { SQLiteCursor cursor = database.queryFinalized("SELECT data FROM wallpapers WHERE 1"); ArrayList wallPapers = new ArrayList(); while (cursor.next()) { - byte[] bytes = cursor.byteArrayValue(0); - if (bytes != null) { - SerializedData data = new SerializedData(bytes); - TLRPC.WallPaper wallPaper = (TLRPC.WallPaper)TLClassStore.Instance().TLdeserialize(data, data.readInt32()); + ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); + if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { + TLRPC.WallPaper wallPaper = (TLRPC.WallPaper) TLClassStore.Instance().TLdeserialize(data, data.readInt32()); wallPapers.add(wallPaper); } + buffersStorage.reuseFreeBuffer(data); } cursor.dispose(); NotificationCenter.getInstance().postNotificationName(wallpapersDidLoaded, wallPapers); @@ -342,12 +354,12 @@ public class MessagesStorage { final TLRPC.photos_Photos res = new TLRPC.photos_Photos(); while (cursor.next()) { - byte[] messageData = cursor.byteArrayValue(0); - if (messageData != null) { - SerializedData data = new SerializedData(messageData); + ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); + if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { TLRPC.Photo photo = (TLRPC.Photo)TLClassStore.Instance().TLdeserialize(data, data.readInt32()); res.photos.add(photo); } + buffersStorage.reuseFreeBuffer(data); } cursor.dispose(); @@ -392,13 +404,13 @@ public class MessagesStorage { continue; } state.requery(); - SerializedData data = new SerializedData(); + ByteBufferDesc data = buffersStorage.getFreeBuffer(photo.getObjectSize()); photo.serializeToStream(data); state.bindInteger(1, uid); state.bindLong(2, photo.id); - byte[] bytes = data.toByteArray(); - state.bindByteArray(3, bytes); + state.bindByteBuffer(3, data.buffer); state.step(); + buffersStorage.reuseFreeBuffer(data); } state.dispose(); } catch (Exception e) { @@ -423,13 +435,16 @@ public class MessagesStorage { if (cursor.next()) { taskId = cursor.longValue(0); date = cursor.intValue(1); - byte[] data = cursor.byteArrayValue(2); - SerializedData serializedData = new SerializedData(data); - arr = new ArrayList(); - int count = data.length / 4; - for (int a = 0; a < count; a++) { - arr.add(serializedData.readInt32()); + + int length = 0; + ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(2)); + if ((length = cursor.byteBufferValue(2, data.buffer)) != 0) { + arr = new ArrayList(); + for (int a = 0; a < length / 4; a++) { + arr.add(data.readInt32()); + } } + buffersStorage.reuseFreeBuffer(data); } cursor.dispose(); MessagesController.getInstance().processLoadedDeleteTask(taskId, date, arr); @@ -473,22 +488,22 @@ public class MessagesStorage { for (int a = 0; a < messages.size(); a++) { int key = messages.keyAt(a); ArrayList arr = messages.get(key); - SerializedData data = new SerializedData(); + ByteBufferDesc data = buffersStorage.getFreeBuffer(404); + int count = 0; for (int b = 0; b < arr.size(); b++) { int mid = arr.get(b); data.writeInt32(mid); + count++; if (b == arr.size() - 1 || b != 0 && b % 100 == 0) { state.requery(); - byte[] toDb = data.toByteArray(); + data.limit(count * 4); state.bindInteger(1, key); - state.bindByteArray(2, toDb); + state.bindByteBuffer(2, data.buffer); state.step(); - - if (b != arr.size() - 1) { - data = new SerializedData(); - } + count = 0; } } + buffersStorage.reuseFreeBuffer(data); } state.dispose(); database.commitTransaction(); @@ -613,12 +628,13 @@ public class MessagesStorage { } } SQLitePreparedStatement state = database.executeFast("REPLACE INTO chat_settings VALUES(?, ?)"); - SerializedData data = new SerializedData(); + ByteBufferDesc data = buffersStorage.getFreeBuffer(info.getObjectSize()); info.serializeToStream(data); state.bindInteger(1, chat_id); - state.bindByteArray(2, data.toByteArray()); + state.bindByteBuffer(2, data.buffer); state.step(); state.dispose(); + buffersStorage.reuseFreeBuffer(data); } catch (Exception e) { FileLog.e("tmessages", e); } @@ -635,11 +651,11 @@ public class MessagesStorage { TLRPC.ChatParticipants info = null; ArrayList loadedUsers = new ArrayList(); if (cursor.next()) { - byte[] userData = cursor.byteArrayValue(0); - if (userData != null) { - SerializedData data = new SerializedData(userData); + ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); + if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { info = (TLRPC.ChatParticipants)TLClassStore.Instance().TLdeserialize(data, data.readInt32()); } + buffersStorage.reuseFreeBuffer(data); } cursor.dispose(); if (info != null) { @@ -669,12 +685,13 @@ public class MessagesStorage { }); SQLitePreparedStatement state = database.executeFast("REPLACE INTO chat_settings VALUES(?, ?)"); - SerializedData data = new SerializedData(); + ByteBufferDesc data = buffersStorage.getFreeBuffer(info.getObjectSize()); info.serializeToStream(data); state.bindInteger(1, chat_id); - state.bindByteArray(2, data.toByteArray()); + state.bindByteBuffer(2, data.buffer); state.step(); state.dispose(); + buffersStorage.reuseFreeBuffer(data); } } catch (Exception e) { FileLog.e("tmessages", e); @@ -692,11 +709,11 @@ public class MessagesStorage { TLRPC.ChatParticipants info = null; ArrayList loadedUsers = new ArrayList(); if (cursor.next()) { - byte[] userData = cursor.byteArrayValue(0); - if (userData != null) { - SerializedData data = new SerializedData(userData); + ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); + if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { info = (TLRPC.ChatParticipants)TLClassStore.Instance().TLdeserialize(data, data.readInt32()); } + buffersStorage.reuseFreeBuffer(data); } cursor.dispose(); @@ -711,15 +728,15 @@ public class MessagesStorage { if (usersToLoad.length() != 0) { cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, status FROM users WHERE uid IN(%s)", usersToLoad)); while (cursor.next()) { - byte[] userData = cursor.byteArrayValue(0); - if (userData != null) { - SerializedData data = new SerializedData(userData); + ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); + if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { TLRPC.User user = (TLRPC.User)TLClassStore.Instance().TLdeserialize(data, data.readInt32()); loadedUsers.add(user); if (user.status != null) { user.status.expires = cursor.intValue(1); } } + buffersStorage.reuseFreeBuffer(data); } cursor.dispose(); } @@ -801,19 +818,18 @@ public class MessagesStorage { String[] args = name.split(" "); for (String str : args) { if (str.startsWith(q)) { - byte[] userData = cursor.byteArrayValue(0); - if (userData != null) { - SerializedData data = new SerializedData(userData); + ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); + if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { TLRPC.User user = (TLRPC.User)TLClassStore.Instance().TLdeserialize(data, data.readInt32()); - if (user.id == UserConfig.getClientUserId()) { - continue; + if (user.id != UserConfig.getClientUserId()) { + if (user.status != null) { + user.status.expires = cursor.intValue(1); + } + resultArrayNames.add(Utilities.generateSearchName(user.first_name, user.last_name, q)); + resultArray.add(user); } - if (user.status != null) { - user.status.expires = cursor.intValue(1); - } - resultArrayNames.add(Utilities.generateSearchName(user.first_name, user.last_name, q)); - resultArray.add(user); } + buffersStorage.reuseFreeBuffer(data); break; } } @@ -827,17 +843,15 @@ public class MessagesStorage { String[] args = name.split(" "); for (String arg : args) { if (arg.startsWith(q)) { - byte[] chatData = cursor.byteArrayValue(0); - byte[] userData = cursor.byteArrayValue(6); - if (chatData != null && userData != null) { - SerializedData data = new SerializedData(chatData); + ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); + ByteBufferDesc data2 = buffersStorage.getFreeBuffer(cursor.byteArrayLength(6)); + if (data != null && cursor.byteBufferValue(0, data.buffer) != 0 && cursor.byteBufferValue(0, data2.buffer) != 0) { TLRPC.EncryptedChat chat = (TLRPC.EncryptedChat) TLClassStore.Instance().TLdeserialize(data, data.readInt32()); chat.user_id = cursor.intValue(2); chat.a_or_b = cursor.byteArrayValue(3); chat.auth_key = cursor.byteArrayValue(4); chat.ttl = cursor.intValue(5); - SerializedData data2 = new SerializedData(userData); TLRPC.User user = (TLRPC.User)TLClassStore.Instance().TLdeserialize(data2, data2.readInt32()); if (user.status != null) { user.status.expires = cursor.intValue(7); @@ -846,6 +860,8 @@ public class MessagesStorage { resultArray.add(chat); encUsers.add(user); } + buffersStorage.reuseFreeBuffer(data); + buffersStorage.reuseFreeBuffer(data2); break; } } @@ -859,13 +875,13 @@ public class MessagesStorage { String[] args = name.split(" "); for (String arg : args) { if (arg.startsWith(q)) { - byte[] chatData = cursor.byteArrayValue(0); - if (chatData != null) { - SerializedData data = new SerializedData(chatData); + ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); + if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { TLRPC.Chat chat = (TLRPC.Chat) TLClassStore.Instance().TLdeserialize(data, data.readInt32()); resultArrayNames.add(Utilities.generateSearchName(chat.title, null, q)); resultArray.add(chat); } + buffersStorage.reuseFreeBuffer(data); break; } } @@ -1059,15 +1075,15 @@ public class MessagesStorage { if (uids.length() != 0) { cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, status FROM users WHERE uid IN(%s)", uids)); while (cursor.next()) { - byte[] userData = cursor.byteArrayValue(0); - if (userData != null) { - SerializedData data = new SerializedData(userData); + ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); + if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { TLRPC.User user = (TLRPC.User)TLClassStore.Instance().TLdeserialize(data, data.readInt32()); users.add(user); if (user.status != null) { user.status.expires = cursor.intValue(1); } } + buffersStorage.reuseFreeBuffer(data); } cursor.dispose(); } @@ -1155,15 +1171,15 @@ public class MessagesStorage { } while (cursor.next()) { - byte[] messageData = cursor.byteArrayValue(0); - if (messageData != null) { - SerializedData data = new SerializedData(messageData); + ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); + if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { TLRPC.Message message = (TLRPC.Message)TLClassStore.Instance().TLdeserialize(data, data.readInt32()); message.id = cursor.intValue(1); message.dialog_id = uid; res.messages.add(message); fromUser.add(message.from_id); } + buffersStorage.reuseFreeBuffer(data); } cursor.dispose(); @@ -1180,9 +1196,8 @@ public class MessagesStorage { if (usersToLoad.length() != 0) { cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, status FROM users WHERE uid IN(%s)", usersToLoad)); while (cursor.next()) { - byte[] userData = cursor.byteArrayValue(0); - if (userData != null) { - SerializedData data = new SerializedData(userData); + ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); + if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { TLRPC.User user = (TLRPC.User)TLClassStore.Instance().TLdeserialize(data, data.readInt32()); loadedUsers.add(user.id); if (user.status != null) { @@ -1190,6 +1205,7 @@ public class MessagesStorage { } res.users.add(user); } + buffersStorage.reuseFreeBuffer(data); } cursor.dispose(); } @@ -1215,13 +1231,14 @@ public class MessagesStorage { for (TLRPC.Message message : messages) { if (message.media instanceof TLRPC.TL_messageMediaVideo || message.media instanceof TLRPC.TL_messageMediaPhoto) { state2.requery(); - SerializedData data = new SerializedData(); + ByteBufferDesc data = buffersStorage.getFreeBuffer(message.getObjectSize()); message.serializeToStream(data); state2.bindInteger(1, message.id); state2.bindLong(2, uid); state2.bindInteger(3, message.date); - state2.bindByteArray(4, data.toByteArray()); + state2.bindByteBuffer(4, data.buffer); state2.step(); + buffersStorage.reuseFreeBuffer(data); } } state2.dispose(); @@ -1333,9 +1350,8 @@ public class MessagesStorage { } } while (cursor.next()) { - byte[] messageData = cursor.byteArrayValue(1); - if (messageData != null) { - SerializedData data = new SerializedData(messageData); + ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(1)); + if (data != null && cursor.byteBufferValue(1, data.buffer) != 0) { TLRPC.Message message = (TLRPC.Message)TLClassStore.Instance().TLdeserialize(data, data.readInt32()); int read_state = cursor.intValue(0); message.unread = (cursor.intValue(0) != 1); @@ -1364,6 +1380,7 @@ public class MessagesStorage { message.random_id = cursor.longValue(5); } } + buffersStorage.reuseFreeBuffer(data); } cursor.dispose(); @@ -1380,9 +1397,8 @@ public class MessagesStorage { if (usersToLoad.length() != 0) { cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, status FROM users WHERE uid IN(%s)", usersToLoad)); while (cursor.next()) { - byte[] userData = cursor.byteArrayValue(0); - if (userData != null) { - SerializedData data = new SerializedData(userData); + ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); + if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { TLRPC.User user = (TLRPC.User)TLClassStore.Instance().TLdeserialize(data, data.readInt32()); loadedUsers.add(user.id); if (user.status != null) { @@ -1390,6 +1406,7 @@ public class MessagesStorage { } res.users.add(user); } + buffersStorage.reuseFreeBuffer(data); } cursor.dispose(); } @@ -1453,14 +1470,14 @@ public class MessagesStorage { if (id != null) { SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT data FROM sent_files_v2 WHERE uid = '%s' AND type = %d", id, type)); if (cursor.next()) { - byte[] fileData = cursor.byteArrayValue(0); - if (fileData != null) { - SerializedData data = new SerializedData(fileData); + ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); + if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { TLObject file = TLClassStore.Instance().TLdeserialize(data, data.readInt32()); if (file != null) { result.add(file); } } + buffersStorage.reuseFreeBuffer(data); } cursor.dispose(); } @@ -1491,13 +1508,14 @@ public class MessagesStorage { if (id != null) { SQLitePreparedStatement state = database.executeFast("REPLACE INTO sent_files_v2 VALUES(?, ?, ?)"); state.requery(); - SerializedData data = new SerializedData(); + ByteBufferDesc data = buffersStorage.getFreeBuffer(file.getObjectSize()); file.serializeToStream(data); state.bindString(1, id); state.bindInteger(2, type); - state.bindByteArray(3, data.toByteArray()); + state.bindByteBuffer(3, data.buffer); state.step(); state.dispose(); + buffersStorage.reuseFreeBuffer(data); } } catch (Exception e) { FileLog.e("tmessages", e); @@ -1540,22 +1558,25 @@ public class MessagesStorage { SQLitePreparedStatement state = null; try { state = database.executeFast("UPDATE enc_chats SET data = ?, g = ?, authkey = ?, ttl = ? WHERE uid = ?"); - SerializedData data = new SerializedData(); + ByteBufferDesc data = buffersStorage.getFreeBuffer(chat.getObjectSize()); + ByteBufferDesc data2 = buffersStorage.getFreeBuffer(chat.a_or_b != null ? chat.a_or_b.length : 1); + ByteBufferDesc data3 = buffersStorage.getFreeBuffer(chat.auth_key != null ? chat.auth_key.length : 1); chat.serializeToStream(data); - state.bindByteArray(1, data.toByteArray()); + state.bindByteBuffer(1, data.buffer); if (chat.a_or_b != null) { - state.bindByteArray(2, chat.a_or_b); - } else { - state.bindByteArray(2, new byte[1]); + data2.writeRaw(chat.a_or_b); } if (chat.auth_key != null) { - state.bindByteArray(3, chat.auth_key); - } else { - state.bindByteArray(3, new byte[1]); + data3.writeRaw(chat.auth_key); } + state.bindByteBuffer(2, data2.buffer); + state.bindByteBuffer(3, data3.buffer); state.bindInteger(4, chat.ttl); state.bindInteger(5, chat.id); state.step(); + buffersStorage.reuseFreeBuffer(data); + buffersStorage.reuseFreeBuffer(data2); + buffersStorage.reuseFreeBuffer(data3); } catch (Exception e) { FileLog.e("tmessages", e); } finally { @@ -1578,9 +1599,8 @@ public class MessagesStorage { int userToLoad = 0; SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, user, g, authkey, ttl FROM enc_chats WHERE uid = %d", chat_id)); if (cursor.next()) { - byte[] chatData = cursor.byteArrayValue(0); - if (chatData != null) { - SerializedData data = new SerializedData(chatData); + ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); + if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { TLRPC.EncryptedChat chat = (TLRPC.EncryptedChat)TLClassStore.Instance().TLdeserialize(data, data.readInt32()); result.add(chat); chat.user_id = cursor.intValue(1); @@ -1589,20 +1609,21 @@ public class MessagesStorage { chat.auth_key = cursor.byteArrayValue(3); chat.ttl = cursor.intValue(4); } + buffersStorage.reuseFreeBuffer(data); } cursor.dispose(); if (userToLoad != 0) { cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, status FROM users WHERE uid = %d", userToLoad)); if (cursor.next()) { - byte[] userData = cursor.byteArrayValue(0); - if (userData != null) { - SerializedData data = new SerializedData(userData); + ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); + if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { TLRPC.User user = (TLRPC.User)TLClassStore.Instance().TLdeserialize(data, data.readInt32()); if (user.status != null) { user.status.expires = cursor.intValue(1); } result.add(user); } + buffersStorage.reuseFreeBuffer(data); } cursor.dispose(); @@ -1628,7 +1649,10 @@ public class MessagesStorage { public void run() { try { SQLitePreparedStatement state = database.executeFast("REPLACE INTO enc_chats VALUES(?, ?, ?, ?, ?, ?, ?)"); - SerializedData data = new SerializedData(); + ByteBufferDesc data = buffersStorage.getFreeBuffer(chat.getObjectSize()); + ByteBufferDesc data2 = buffersStorage.getFreeBuffer(chat.a_or_b != null ? chat.a_or_b.length : 1); + ByteBufferDesc data3 = buffersStorage.getFreeBuffer(chat.auth_key != null ? chat.auth_key.length : 1); + chat.serializeToStream(data); state.bindInteger(1, chat.id); state.bindInteger(2, user.id); @@ -1638,20 +1662,21 @@ public class MessagesStorage { } else { state.bindString(3, ""); } - state.bindByteArray(4, data.toByteArray()); + state.bindByteBuffer(4, data.buffer); if (chat.a_or_b != null) { - state.bindByteArray(5, chat.a_or_b); - } else { - state.bindByteArray(5, new byte[1]); + data2.writeRaw(chat.a_or_b); } if (chat.auth_key != null) { - state.bindByteArray(6, chat.auth_key); - } else { - state.bindByteArray(6, new byte[1]); + data3.writeRaw(chat.auth_key); } + state.bindByteBuffer(5, data2.buffer); + state.bindByteBuffer(6, data3.buffer); state.bindInteger(7, chat.ttl); state.step(); state.dispose(); + buffersStorage.reuseFreeBuffer(data); + buffersStorage.reuseFreeBuffer(data2); + buffersStorage.reuseFreeBuffer(data3); if (dialog != null) { state = database.executeFast("REPLACE INTO dialogs VALUES(?, ?, ?, ?)"); @@ -1681,7 +1706,7 @@ public class MessagesStorage { SQLitePreparedStatement state = database.executeFast("REPLACE INTO users VALUES(?, ?, ?, ?)"); for (TLRPC.User user : users) { state.requery(); - SerializedData data = new SerializedData(); + ByteBufferDesc data = buffersStorage.getFreeBuffer(user.getObjectSize()); user.serializeToStream(data); state.bindInteger(1, user.id); if (user.first_name != null && user.last_name != null) { @@ -1695,8 +1720,9 @@ public class MessagesStorage { } else { state.bindInteger(3, 0); } - state.bindByteArray(4, data.toByteArray()); + state.bindByteBuffer(4, data.buffer); state.step(); + buffersStorage.reuseFreeBuffer(data); } state.dispose(); } @@ -1704,7 +1730,7 @@ public class MessagesStorage { SQLitePreparedStatement state = database.executeFast("REPLACE INTO chats VALUES(?, ?, ?)"); for (TLRPC.Chat chat : chats) { state.requery(); - SerializedData data = new SerializedData(); + ByteBufferDesc data = buffersStorage.getFreeBuffer(chat.getObjectSize()); chat.serializeToStream(data); state.bindInteger(1, chat.id); if (chat.title != null) { @@ -1713,8 +1739,9 @@ public class MessagesStorage { } else { state.bindString(2, ""); } - state.bindByteArray(3, data.toByteArray()); + state.bindByteBuffer(3, data.buffer); state.step(); + buffersStorage.reuseFreeBuffer(data); } state.dispose(); } @@ -1850,7 +1877,7 @@ public class MessagesStorage { messageId = message.local_id; } - SerializedData data = new SerializedData(); + ByteBufferDesc data = buffersStorage.getFreeBuffer(message.getObjectSize()); message.serializeToStream(data); TLRPC.Message lastMessage = messagesMap.get(dialog_id); if (lastMessage == null || message.date > lastMessage.date) { @@ -1861,8 +1888,7 @@ public class MessagesStorage { state.bindInteger(3, (message.unread ? 0 : 1)); state.bindInteger(4, message.send_state); state.bindInteger(5, message.date); - byte[] bytes = data.toByteArray(); - state.bindByteArray(6, bytes); + state.bindByteBuffer(6, data.buffer); state.bindInteger(7, (message.out ? 1 : 0)); state.bindInteger(8, message.ttl); state.step(); @@ -1879,9 +1905,10 @@ public class MessagesStorage { state2.bindInteger(1, messageId); state2.bindLong(2, dialog_id); state2.bindInteger(3, message.date); - state2.bindByteArray(4, bytes); + state2.bindByteBuffer(4, data.buffer); state2.step(); } + buffersStorage.reuseFreeBuffer(data); } state.dispose(); state2.dispose(); @@ -2094,9 +2121,8 @@ public class MessagesStorage { ArrayList loadedUsers = new ArrayList(); SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, status FROM users WHERE uid IN(%s)", ids)); while (cursor.next()) { - byte[] userData = cursor.byteArrayValue(0); - if (userData != null) { - SerializedData data = new SerializedData(userData); + ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); + if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { TLRPC.User user = (TLRPC.User)TLClassStore.Instance().TLdeserialize(data, data.readInt32()); loadedUsers.add(user); if (user.status != null) { @@ -2110,6 +2136,7 @@ public class MessagesStorage { user.photo = updateUser.photo; } } + buffersStorage.reuseFreeBuffer(data); } cursor.dispose(); if (!loadedUsers.isEmpty()) { @@ -2119,7 +2146,7 @@ public class MessagesStorage { SQLitePreparedStatement state = database.executeFast("REPLACE INTO users VALUES(?, ?, ?, ?)"); for (TLRPC.User user : loadedUsers) { state.requery(); - SerializedData data = new SerializedData(); + ByteBufferDesc data = buffersStorage.getFreeBuffer(user.getObjectSize()); user.serializeToStream(data); state.bindInteger(1, user.id); if (user.first_name != null && user.last_name != null) { @@ -2133,8 +2160,9 @@ public class MessagesStorage { } else { state.bindInteger(3, 0); } - state.bindByteArray(4, data.toByteArray()); + state.bindByteBuffer(4, data.buffer); state.step(); + buffersStorage.reuseFreeBuffer(data); } state.dispose(); if (withTransaction) { @@ -2325,9 +2353,8 @@ public class MessagesStorage { dialog.last_message_date = cursor.intValue(3); dialogs.dialogs.add(dialog); - byte[] messageData = cursor.byteArrayValue(4); - if (messageData != null) { - SerializedData data = new SerializedData(messageData); + ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(4)); + if (data != null && cursor.byteBufferValue(4, data.buffer) != 0) { TLRPC.Message message = (TLRPC.Message)TLClassStore.Instance().TLdeserialize(data, data.readInt32()); message.unread = (cursor.intValue(5) != 1); message.id = cursor.intValue(6); @@ -2348,6 +2375,7 @@ public class MessagesStorage { } } } + buffersStorage.reuseFreeBuffer(data); int lower_id = (int)dialog.id; if (lower_id != 0) { @@ -2379,9 +2407,8 @@ public class MessagesStorage { } cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, user, g, authkey, ttl FROM enc_chats WHERE uid IN(%s)", toLoad)); while (cursor.next()) { - byte[] chatData = cursor.byteArrayValue(0); - if (chatData != null) { - SerializedData data = new SerializedData(chatData); + ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); + if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { TLRPC.EncryptedChat chat = (TLRPC.EncryptedChat)TLClassStore.Instance().TLdeserialize(data, data.readInt32()); encryptedChats.add(chat); chat.user_id = cursor.intValue(1); @@ -2392,6 +2419,7 @@ public class MessagesStorage { chat.auth_key = cursor.byteArrayValue(3); chat.ttl = cursor.intValue(4); } + buffersStorage.reuseFreeBuffer(data); } cursor.dispose(); } @@ -2406,12 +2434,12 @@ public class MessagesStorage { } cursor = database.queryFinalized(String.format(Locale.US, "SELECT data FROM chats WHERE uid IN(%s)", toLoad)); while (cursor.next()) { - byte[] chatData = cursor.byteArrayValue(0); - if (chatData != null) { - SerializedData data = new SerializedData(chatData); + ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); + if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { TLRPC.Chat chat = (TLRPC.Chat)TLClassStore.Instance().TLdeserialize(data, data.readInt32()); dialogs.chats.add(chat); } + buffersStorage.reuseFreeBuffer(data); } cursor.dispose(); } @@ -2426,15 +2454,15 @@ public class MessagesStorage { } cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, status FROM users WHERE uid IN(%s)", toLoad)); while (cursor.next()) { - byte[] userData = cursor.byteArrayValue(0); - if (userData != null) { - SerializedData data = new SerializedData(userData); + ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); + if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { TLRPC.User user = (TLRPC.User)TLClassStore.Instance().TLdeserialize(data, data.readInt32()); if (user.status != null) { user.status.expires = cursor.intValue(1); } dialogs.users.add(user); } + buffersStorage.reuseFreeBuffer(data); } cursor.dispose(); } @@ -2493,15 +2521,14 @@ public class MessagesStorage { SQLitePreparedStatement state2 = database.executeFast("REPLACE INTO media VALUES(?, ?, ?, ?)"); for (TLRPC.Message message : messages.messages) { state.requery(); - SerializedData data = new SerializedData(); + ByteBufferDesc data = buffersStorage.getFreeBuffer(message.getObjectSize()); message.serializeToStream(data); state.bindInteger(1, message.id); state.bindLong(2, dialog_id); state.bindInteger(3, (message.unread ? 0 : 1)); state.bindInteger(4, message.send_state); state.bindInteger(5, message.date); - byte[] bytes = data.toByteArray(); - state.bindByteArray(6, bytes); + state.bindByteBuffer(6, data.buffer); state.bindInteger(7, (message.out ? 1 : 0)); state.bindInteger(8, 0); state.step(); @@ -2511,9 +2538,10 @@ public class MessagesStorage { state2.bindInteger(1, message.id); state2.bindLong(2, dialog_id); state2.bindInteger(3, message.date); - state2.bindByteArray(4, bytes); + state2.bindByteBuffer(4, data.buffer); state2.step(); } + buffersStorage.reuseFreeBuffer(data); } state.dispose(); state2.dispose(); @@ -2522,7 +2550,7 @@ public class MessagesStorage { SQLitePreparedStatement state = database.executeFast("REPLACE INTO users VALUES(?, ?, ?, ?)"); for (TLRPC.User user : messages.users) { state.requery(); - SerializedData data = new SerializedData(); + ByteBufferDesc data = buffersStorage.getFreeBuffer(user.getObjectSize()); user.serializeToStream(data); state.bindInteger(1, user.id); if (user.first_name != null && user.last_name != null) { @@ -2536,8 +2564,9 @@ public class MessagesStorage { } else { state.bindInteger(3, 0); } - state.bindByteArray(4, data.toByteArray()); + state.bindByteBuffer(4, data.buffer); state.step(); + buffersStorage.reuseFreeBuffer(data); } state.dispose(); } @@ -2545,7 +2574,7 @@ public class MessagesStorage { SQLitePreparedStatement state = database.executeFast("REPLACE INTO chats VALUES(?, ?, ?)"); for (TLRPC.Chat chat : messages.chats) { state.requery(); - SerializedData data = new SerializedData(); + ByteBufferDesc data = buffersStorage.getFreeBuffer(chat.getObjectSize()); chat.serializeToStream(data); state.bindInteger(1, chat.id); if (chat.title != null) { @@ -2554,8 +2583,9 @@ public class MessagesStorage { } else { state.bindString(2, ""); } - state.bindByteArray(3, data.toByteArray()); + state.bindByteBuffer(3, data.buffer); state.step(); + buffersStorage.reuseFreeBuffer(data); } state.dispose(); } @@ -2588,9 +2618,8 @@ public class MessagesStorage { dialog.last_message_date = cursor.intValue(3); dialogs.dialogs.add(dialog); - byte[] messageData = cursor.byteArrayValue(4); - if (messageData != null) { - SerializedData data = new SerializedData(messageData); + ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(4)); + if (data != null && cursor.byteBufferValue(4, data.buffer) != 0) { TLRPC.Message message = (TLRPC.Message)TLClassStore.Instance().TLdeserialize(data, data.readInt32()); if (message != null) { message.unread = (cursor.intValue(5) != 1); @@ -2613,6 +2642,7 @@ public class MessagesStorage { } } } + buffersStorage.reuseFreeBuffer(data); int lower_id = (int)dialog.id; if (lower_id != 0) { @@ -2645,9 +2675,8 @@ public class MessagesStorage { cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, user, g, authkey, ttl FROM enc_chats WHERE uid IN(%s)", toLoad)); while (cursor.next()) { try { - byte[] chatData = cursor.byteArrayValue(0); - if (chatData != null) { - SerializedData data = new SerializedData(chatData); + ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); + if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { TLRPC.EncryptedChat chat = (TLRPC.EncryptedChat)TLClassStore.Instance().TLdeserialize(data, data.readInt32()); if (chat != null) { encryptedChats.add(chat); @@ -2660,6 +2689,7 @@ public class MessagesStorage { chat.ttl = cursor.intValue(4); } } + buffersStorage.reuseFreeBuffer(data); } catch (Exception e) { FileLog.e("tmessages", e); } @@ -2678,14 +2708,14 @@ public class MessagesStorage { cursor = database.queryFinalized(String.format(Locale.US, "SELECT data FROM chats WHERE uid IN(%s)", toLoad)); while (cursor.next()) { try { - byte[] chatData = cursor.byteArrayValue(0); - if (chatData != null) { - SerializedData data = new SerializedData(chatData); + ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); + if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { TLRPC.Chat chat = (TLRPC.Chat)TLClassStore.Instance().TLdeserialize(data, data.readInt32()); if (chat != null) { dialogs.chats.add(chat); } } + buffersStorage.reuseFreeBuffer(data); } catch (Exception e) { FileLog.e("tmessages", e); } @@ -2704,9 +2734,8 @@ public class MessagesStorage { cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, status FROM users WHERE uid IN(%s)", toLoad)); while (cursor.next()) { try { - byte[] userData = cursor.byteArrayValue(0); - if (userData != null) { - SerializedData data = new SerializedData(userData); + ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); + if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { TLRPC.User user = (TLRPC.User)TLClassStore.Instance().TLdeserialize(data, data.readInt32()); if (user != null) { if (user.status != null) { @@ -2715,6 +2744,7 @@ public class MessagesStorage { dialogs.users.add(user); } } + buffersStorage.reuseFreeBuffer(data); } catch (Exception e) { FileLog.e("tmessages", e); } @@ -2766,7 +2796,7 @@ public class MessagesStorage { uid = -dialog.peer.chat_id; } TLRPC.Message message = new_dialogMessage.get(dialog.top_message); - SerializedData data = new SerializedData(); + ByteBufferDesc data = buffersStorage.getFreeBuffer(message.getObjectSize()); message.serializeToStream(data); state.bindInteger(1, message.id); @@ -2774,8 +2804,7 @@ public class MessagesStorage { state.bindInteger(3, (message.unread ? 0 : 1)); state.bindInteger(4, message.send_state); state.bindInteger(5, message.date); - byte[] bytes = data.toByteArray(); - state.bindByteArray(6, bytes); + state.bindByteBuffer(6, data.buffer); state.bindInteger(7, (message.out ? 1 : 0)); state.bindInteger(8, 0); state.step(); @@ -2791,9 +2820,10 @@ public class MessagesStorage { state3.bindLong(1, message.id); state3.bindInteger(2, uid); state3.bindInteger(3, message.date); - state3.bindByteArray(4, bytes); + state3.bindByteBuffer(4, data.buffer); state3.step(); } + buffersStorage.reuseFreeBuffer(data); } state.dispose(); state2.dispose(); @@ -2804,7 +2834,7 @@ public class MessagesStorage { SQLitePreparedStatement state = database.executeFast("REPLACE INTO users VALUES(?, ?, ?, ?)"); for (TLRPC.User user : dialogs.users) { state.requery(); - SerializedData data = new SerializedData(); + ByteBufferDesc data = buffersStorage.getFreeBuffer(user.getObjectSize()); user.serializeToStream(data); state.bindInteger(1, user.id); if (user.first_name != null && user.last_name != null) { @@ -2818,8 +2848,9 @@ public class MessagesStorage { } else { state.bindInteger(3, 0); } - state.bindByteArray(4, data.toByteArray()); + state.bindByteBuffer(4, data.buffer); state.step(); + buffersStorage.reuseFreeBuffer(data); } state.dispose(); } @@ -2828,7 +2859,7 @@ public class MessagesStorage { SQLitePreparedStatement state = database.executeFast("REPLACE INTO chats VALUES(?, ?, ?)"); for (TLRPC.Chat chat : dialogs.chats) { state.requery(); - SerializedData data = new SerializedData(); + ByteBufferDesc data = buffersStorage.getFreeBuffer(chat.getObjectSize()); chat.serializeToStream(data); state.bindInteger(1, chat.id); if (chat.title != null) { @@ -2837,8 +2868,9 @@ public class MessagesStorage { } else { state.bindString(2, ""); } - state.bindByteArray(3, data.toByteArray()); + state.bindByteBuffer(3, data.buffer); state.step(); + buffersStorage.reuseFreeBuffer(data); } state.dispose(); } @@ -2856,9 +2888,8 @@ public class MessagesStorage { try { SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, status FROM users WHERE uid = %d", user_id)); if (cursor.next()) { - byte[] userData = cursor.byteArrayValue(0); - if (userData != null) { - SerializedData data = new SerializedData(userData); + ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); + if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { user = (TLRPC.User) TLClassStore.Instance().TLdeserialize(data, data.readInt32()); if (user != null) { if (user.status != null) { @@ -2866,6 +2897,7 @@ public class MessagesStorage { } } } + buffersStorage.reuseFreeBuffer(data); } cursor.dispose(); } catch (Exception e) { @@ -2888,9 +2920,8 @@ public class MessagesStorage { SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, status FROM users WHERE uid IN (%s)", uidsStr)); while (cursor.next()) { - byte[] userData = cursor.byteArrayValue(0); - if (userData != null) { - SerializedData data = new SerializedData(userData); + ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); + if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { TLRPC.User user = (TLRPC.User) TLClassStore.Instance().TLdeserialize(data, data.readInt32()); if (user != null) { if (user.status != null) { @@ -2899,12 +2930,15 @@ public class MessagesStorage { users.add(user); } else { error[0] = true; + buffersStorage.reuseFreeBuffer(data); break; } } else { error[0] = true; + buffersStorage.reuseFreeBuffer(data); break; } + buffersStorage.reuseFreeBuffer(data); } cursor.dispose(); } catch (Exception e) { @@ -2919,11 +2953,11 @@ public class MessagesStorage { try { SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT data FROM chats WHERE uid = %d", chat_id)); if (cursor.next()) { - byte[] chatData = cursor.byteArrayValue(0); - if (chatData != null) { - SerializedData data = new SerializedData(chatData); + ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); + if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { chat = (TLRPC.Chat) TLClassStore.Instance().TLdeserialize(data, data.readInt32()); } + buffersStorage.reuseFreeBuffer(data); } cursor.dispose(); } catch (Exception e) { @@ -2937,9 +2971,8 @@ public class MessagesStorage { try { SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, user, g, authkey, ttl FROM enc_chats WHERE uid = %d", chat_id)); if (cursor.next()) { - byte[] chatData = cursor.byteArrayValue(0); - if (chatData != null) { - SerializedData data = new SerializedData(chatData); + ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0)); + if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) { chat = (TLRPC.EncryptedChat) TLClassStore.Instance().TLdeserialize(data, data.readInt32()); if (chat != null) { chat.user_id = cursor.intValue(1); @@ -2948,6 +2981,7 @@ public class MessagesStorage { chat.ttl = cursor.intValue(4); } } + buffersStorage.reuseFreeBuffer(data); } cursor.dispose(); } catch (Exception e) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/NativeLoader.java b/TMessagesProj/src/main/java/org/telegram/android/NativeLoader.java similarity index 98% rename from TMessagesProj/src/main/java/org/telegram/messenger/NativeLoader.java rename to TMessagesProj/src/main/java/org/telegram/android/NativeLoader.java index 58a966076..ab7dc59cc 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/NativeLoader.java +++ b/TMessagesProj/src/main/java/org/telegram/android/NativeLoader.java @@ -6,12 +6,14 @@ * Copyright Nikolai Kudashov, 2013-2014. */ -package org.telegram.messenger; +package org.telegram.android; import android.content.Context; import android.content.pm.ApplicationInfo; import android.os.Build; +import org.telegram.messenger.FileLog; + import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationsService.java b/TMessagesProj/src/main/java/org/telegram/android/NotificationsService.java similarity index 94% rename from TMessagesProj/src/main/java/org/telegram/messenger/NotificationsService.java rename to TMessagesProj/src/main/java/org/telegram/android/NotificationsService.java index 0b8e145db..a790c7983 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationsService.java +++ b/TMessagesProj/src/main/java/org/telegram/android/NotificationsService.java @@ -6,13 +6,14 @@ * Copyright Nikolai Kudashov, 2013-2014. */ -package org.telegram.messenger; +package org.telegram.android; import android.app.Service; import android.content.Intent; import android.content.SharedPreferences; import android.os.IBinder; +import org.telegram.messenger.FileLog; import org.telegram.ui.ApplicationLoader; public class NotificationsService extends Service { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ScreenReceiver.java b/TMessagesProj/src/main/java/org/telegram/android/ScreenReceiver.java similarity index 77% rename from TMessagesProj/src/main/java/org/telegram/messenger/ScreenReceiver.java rename to TMessagesProj/src/main/java/org/telegram/android/ScreenReceiver.java index b557d0e5f..7a357627d 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ScreenReceiver.java +++ b/TMessagesProj/src/main/java/org/telegram/android/ScreenReceiver.java @@ -6,12 +6,14 @@ * Copyright Nikolai Kudashov, 2013-2014. */ -package org.telegram.messenger; +package org.telegram.android; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; +import org.telegram.messenger.ConnectionsManager; +import org.telegram.messenger.FileLog; import org.telegram.ui.ApplicationLoader; public class ScreenReceiver extends BroadcastReceiver { @@ -19,13 +21,11 @@ public class ScreenReceiver extends BroadcastReceiver { public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) { FileLog.e("tmessages", "screen off"); - if (ConnectionsManager.lastPauseTime == 0) { - ConnectionsManager.lastPauseTime = System.currentTimeMillis(); - } + ConnectionsManager.getInstance().setAppPaused(true, true); ApplicationLoader.isScreenOn = false; } else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) { FileLog.e("tmessages", "screen on"); - ConnectionsManager.resetLastPauseTime(); + ConnectionsManager.getInstance().setAppPaused(false, true); ApplicationLoader.isScreenOn = true; } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/SmsListener.java b/TMessagesProj/src/main/java/org/telegram/android/SmsListener.java similarity index 92% rename from TMessagesProj/src/main/java/org/telegram/messenger/SmsListener.java rename to TMessagesProj/src/main/java/org/telegram/android/SmsListener.java index 1a5a6f46b..6489456b8 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/SmsListener.java +++ b/TMessagesProj/src/main/java/org/telegram/android/SmsListener.java @@ -6,7 +6,7 @@ * Copyright Nikolai Kudashov, 2013. */ -package org.telegram.messenger; +package org.telegram.android; import android.content.BroadcastReceiver; import android.content.Context; @@ -15,6 +15,9 @@ import android.content.SharedPreferences; import android.os.Bundle; import android.telephony.SmsMessage; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.NotificationCenter; + import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -25,7 +28,7 @@ public class SmsListener extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if(intent.getAction().equals("android.provider.Telephony.SMS_RECEIVED")) { - if (!Utilities.isWaitingForSms()) { + if (!AndroidUtilities.isWaitingForSms()) { return; } Bundle bundle = intent.getExtras(); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/Action.java b/TMessagesProj/src/main/java/org/telegram/messenger/Action.java index 69fdfca64..61ed9b70d 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/Action.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/Action.java @@ -25,6 +25,4 @@ public class Action { public void cancel() { } - - public int state; } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/BuffersStorage.java b/TMessagesProj/src/main/java/org/telegram/messenger/BuffersStorage.java index d09803789..5c39ae078 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/BuffersStorage.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/BuffersStorage.java @@ -18,6 +18,8 @@ public class BuffersStorage { private final ArrayList freeBuffers16384; private final ArrayList freeBuffers32768; private final ArrayList freeBuffersBig; + private boolean isThreadSafe; + private final static Integer sync = 1; private static volatile BuffersStorage Instance = null; public static BuffersStorage getInstance() { @@ -26,14 +28,15 @@ public class BuffersStorage { synchronized (BuffersStorage.class) { localInstance = Instance; if (localInstance == null) { - Instance = localInstance = new BuffersStorage(); + Instance = localInstance = new BuffersStorage(true); } } } return localInstance; } - public BuffersStorage() { + public BuffersStorage(boolean threadSafe) { + isThreadSafe = threadSafe; freeBuffers128 = new ArrayList(); freeBuffers1024 = new ArrayList(); freeBuffers4096 = new ArrayList(); @@ -44,91 +47,58 @@ public class BuffersStorage { for (int a = 0; a < 5; a++) { freeBuffers128.add(new ByteBufferDesc(128)); } -// for (int a = 0; a < 5; a++) { -// freeBuffers1024.add(new ByteBufferDesc(1024 + 200)); -// } -// for (int a = 0; a < 2; a++) { -// freeBuffers4096.add(new ByteBufferDesc(4096 + 200)); -// } -// for (int a = 0; a < 2; a++) { -// freeBuffers16384.add(new ByteBufferDesc(16384 + 200)); -// } -// for (int a = 0; a < 2; a++) { -// freeBuffers32768.add(new ByteBufferDesc(40000)); -// } } public ByteBufferDesc getFreeBuffer(int size) { + if (size <= 0) { + return null; + } + int byteCount = 0; + ArrayList arrayToGetFrom = null; ByteBufferDesc buffer = null; if (size <= 128) { - synchronized (freeBuffers128) { - if (freeBuffers128.size() > 0) { - buffer = freeBuffers128.get(0); - freeBuffers128.remove(0); - } - } - if (buffer == null) { - buffer = new ByteBufferDesc(128); - FileLog.e("tmessages", "create new 128 buffer"); - } + arrayToGetFrom = freeBuffers128; + byteCount = 128; } else if (size <= 1024 + 200) { - synchronized (freeBuffers1024) { - if (freeBuffers1024.size() > 0) { - buffer = freeBuffers1024.get(0); - freeBuffers1024.remove(0); - } - } - if (buffer == null) { - buffer = new ByteBufferDesc(1024 + 200); - FileLog.e("tmessages", "create new 1024 buffer"); - } + arrayToGetFrom = freeBuffers1024; + byteCount = 1024 + 200; } else if (size <= 4096 + 200) { - synchronized (freeBuffers4096) { - if (freeBuffers4096.size() > 0) { - buffer = freeBuffers4096.get(0); - freeBuffers4096.remove(0); - } - } - if (buffer == null) { - buffer = new ByteBufferDesc(4096 + 200); - FileLog.e("tmessages", "create new 4096 buffer"); - } + arrayToGetFrom = freeBuffers4096; + byteCount = 4096 + 200; } else if (size <= 16384 + 200) { - synchronized (freeBuffers16384) { - if (freeBuffers16384.size() > 0) { - buffer = freeBuffers16384.get(0); - freeBuffers16384.remove(0); - } - } - if (buffer == null) { - buffer = new ByteBufferDesc(16384 + 200); - FileLog.e("tmessages", "create new 16384 buffer"); - } + arrayToGetFrom = freeBuffers16384; + byteCount = 16384 + 200; } else if (size <= 40000) { - synchronized (freeBuffers32768) { - if (freeBuffers32768.size() > 0) { - buffer = freeBuffers32768.get(0); - freeBuffers32768.remove(0); - } - } - if (buffer == null) { - buffer = new ByteBufferDesc(40000); - FileLog.e("tmessages", "create new 40000 buffer"); - } + arrayToGetFrom = freeBuffers32768; + byteCount = 40000; } else if (size <= 280000) { - synchronized (freeBuffersBig) { - if (freeBuffersBig.size() > 0) { - buffer = freeBuffersBig.get(0); - freeBuffersBig.remove(0); - } - } - if (buffer == null) { - buffer = new ByteBufferDesc(280000); - FileLog.e("tmessages", "create new big buffer"); - } + arrayToGetFrom = freeBuffersBig; + byteCount = 280000; } else { buffer = new ByteBufferDesc(size); } + + if (arrayToGetFrom != null) { + if (isThreadSafe) { + synchronized (sync) { + if (arrayToGetFrom.size() > 0) { + buffer = arrayToGetFrom.get(0); + arrayToGetFrom.remove(0); + } + } + } else { + if (arrayToGetFrom.size() > 0) { + buffer = arrayToGetFrom.get(0); + arrayToGetFrom.remove(0); + } + } + + if (buffer == null) { + buffer = new ByteBufferDesc(byteCount); + FileLog.e("tmessages", "create new " + byteCount + " buffer"); + } + } + buffer.buffer.limit(size).rewind(); return buffer; } @@ -137,40 +107,34 @@ public class BuffersStorage { if (buffer == null) { return; } + int maxCount = 10; + ArrayList arrayToReuse = null; if (buffer.buffer.capacity() == 128) { - synchronized (freeBuffers128) { - if (freeBuffers128.size() < 10) { - freeBuffers128.add(buffer); - } - } + arrayToReuse = freeBuffers128; } else if (buffer.buffer.capacity() == 1024 + 200) { - synchronized (freeBuffers1024) { - if (freeBuffers1024.size() < 10) { - freeBuffers1024.add(buffer); - } - } - } else if (buffer.buffer.capacity() == 4096 + 200) { - synchronized (freeBuffers4096) { - if (freeBuffers4096.size() < 10) { - freeBuffers4096.add(buffer); - } - } + arrayToReuse = freeBuffers1024; + } if (buffer.buffer.capacity() == 4096 + 200) { + arrayToReuse = freeBuffers4096; } else if (buffer.buffer.capacity() == 16384 + 200) { - synchronized (freeBuffers16384) { - if (freeBuffers16384.size() < 10) { - freeBuffers16384.add(buffer); - } - } + arrayToReuse = freeBuffers16384; } else if (buffer.buffer.capacity() == 40000) { - synchronized (freeBuffers32768) { - if (freeBuffers32768.size() < 10) { - freeBuffers32768.add(buffer); - } - } + arrayToReuse = freeBuffers32768; } else if (buffer.buffer.capacity() == 280000) { - synchronized (freeBuffersBig) { - if (freeBuffersBig.size() < 4) { - freeBuffersBig.add(buffer); + arrayToReuse = freeBuffersBig; + maxCount = 10; + } + if (arrayToReuse != null) { + if (isThreadSafe) { + synchronized (sync) { + if (arrayToReuse.size() < maxCount) { + arrayToReuse.add(buffer); + } else { + FileLog.e("tmessages", "too more"); + } + } + } else { + if (arrayToReuse.size() < maxCount) { + arrayToReuse.add(buffer); } } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ByteBufferDesc.java b/TMessagesProj/src/main/java/org/telegram/messenger/ByteBufferDesc.java index 036539927..f36049bc8 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ByteBufferDesc.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ByteBufferDesc.java @@ -25,6 +25,11 @@ public class ByteBufferDesc extends AbsSerializedData { justCalc = calculate; } + public ByteBufferDesc(byte[] bytes) { + buffer = ByteBuffer.wrap(bytes); + buffer.order(ByteOrder.LITTLE_ENDIAN); + } + public int position() { return buffer.position(); } @@ -397,11 +402,13 @@ public class ByteBufferDesc extends AbsSerializedData { sl = 4; } ByteBufferDesc b = BuffersStorage.getInstance().getFreeBuffer(l); - int old = buffer.limit(); - buffer.limit(buffer.position() + l); - b.buffer.put(buffer); - buffer.limit(old); - b.buffer.position(0); + if (b != null) { + int old = buffer.limit(); + buffer.limit(buffer.position() + l); + b.buffer.put(buffer); + buffer.limit(old); + b.buffer.position(0); + } int i = sl; while((l + i) % 4 != 0) { buffer.get(); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ConnectionsManager.java b/TMessagesProj/src/main/java/org/telegram/messenger/ConnectionsManager.java index a35f25703..9d13b642a 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ConnectionsManager.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ConnectionsManager.java @@ -14,13 +14,15 @@ import android.content.pm.PackageInfo; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.os.Build; +import android.os.PowerManager; import android.util.Base64; +import org.telegram.android.ContactsController; +import org.telegram.android.MessagesController; 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.concurrent.ConcurrentHashMap; @@ -34,11 +36,10 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection. private ArrayList destroyingSessions = new ArrayList(); private HashMap> quickAckIdToRequestIds = 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 volatile int connectionState = 2; private ArrayList requestQueue = new ArrayList(); private ArrayList runningRequests = new ArrayList(); @@ -47,17 +48,17 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection. private ArrayList unknownDatacenterIds = new ArrayList(); private ArrayList neededDatacenterIds = new ArrayList(); private ArrayList unauthorizedDatacenterIds = new ArrayList(); - final HashMap> genericMessagesToDatacenters = new HashMap>(); + private final HashMap> genericMessagesToDatacenters = new HashMap>(); 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 static final int DC_UPDATE_TIME = 60 * 60; + protected int currentDatacenterId; + protected int movingToDatacenterId; private long lastOutgoingMessageId = 0; private int isTestBackend = 0; - public int timeDifference = 0; - public int currentPingTime; + private int timeDifference = 0; + private int currentPingTime; private int lastDestroySessionRequestTime; private boolean updatingDcSettings = false; private int updatingDcStartTime = 0; @@ -69,12 +70,17 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection. private boolean paused = false; private long lastPingTime = System.currentTimeMillis(); private long lastPushPingTime = 0; + private boolean pushMessagesReceived = true; private boolean sendingPushPing = false; private int nextSleepTimeout = 30000; private long nextPingId = 0; - public static long lastPauseTime = System.currentTimeMillis(); - public static boolean appPaused = true; + private long lastPauseTime = System.currentTimeMillis(); + private boolean appPaused = true; + + private volatile long nextCallToken = 1; + + private PowerManager.WakeLock wakeLock = null; private static volatile ConnectionsManager Instance = null; public static ConnectionsManager getInstance() { @@ -90,18 +96,18 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection. return localInstance; } - static long t = System.currentTimeMillis(); private Runnable stageRunnable = new Runnable() { @Override public void run() { Utilities.stageQueue.handler.removeCallbacks(stageRunnable); - t = System.currentTimeMillis(); if (datacenters != null) { - if (sendingPushPing && lastPushPingTime < System.currentTimeMillis() - 30000 || Math.abs(lastPushPingTime - System.currentTimeMillis()) > 60000 * 4) { + if (sendingPushPing && lastPushPingTime < System.currentTimeMillis() - 30000 || Math.abs(lastPushPingTime - System.currentTimeMillis()) > 60000 * 3 + 10000) { lastPushPingTime = 0; sendingPushPing = false; + FileLog.e("tmessages", "push ping timeout"); } if (lastPushPingTime < System.currentTimeMillis() - 60000 * 3) { + FileLog.e("tmessages", "time for push ping"); lastPushPingTime = System.currentTimeMillis(); Datacenter datacenter = datacenterWithId(currentDatacenterId); if (datacenter != null) { @@ -112,16 +118,22 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection. long currentTime = System.currentTimeMillis(); if (lastPauseTime != 0 && 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; + boolean dontSleep = !pushMessagesReceived; + if (!dontSleep) { + for (RPCRequest request : runningRequests) { + if (request.rawRequest instanceof TLRPC.TL_get_future_salts) { + dontSleep = true; + } else 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) { + if (request.rawRequest instanceof TLRPC.TL_get_future_salts) { + dontSleep = true; + } else if ((request.flags & RPCRequest.RPCRequestClassDownloadMedia) != 0 || (request.flags & RPCRequest.RPCRequestClassUploadMedia) != 0) { dontSleep = true; break; } @@ -143,7 +155,7 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection. } } else { lastPauseTime += 30 * 1000; - FileLog.e("tmessages", "don't sleep 30 seconds because of upload or download request"); + FileLog.e("tmessages", "don't sleep 30 seconds because of salt, upload or download request"); } } if (paused) { @@ -199,20 +211,35 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection. } Utilities.stageQueue.postRunnable(stageRunnable, 1000); + + PowerManager pm = (PowerManager)ApplicationLoader.applicationContext.getSystemService(Context.POWER_SERVICE); + wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "lock"); + } + + public int getConnectionState() { + return connectionState; + } + + public void setConnectionState(int state) { + connectionState = state; + } + + private void resumeNetworkInternal() { + if (paused) { + lastPauseTime = System.currentTimeMillis(); + nextSleepTimeout = 30000; + FileLog.e("tmessages", "wakeup network in background"); + } else if (lastPauseTime != 0) { + lastPauseTime = System.currentTimeMillis(); + FileLog.e("tmessages", "reset sleep timeout"); + } } public void resumeNetworkMaybe() { Utilities.stageQueue.postRunnable(new Runnable() { @Override public void run() { - if (paused) { - lastPauseTime = System.currentTimeMillis(); - nextSleepTimeout = 30000; - FileLog.e("tmessages", "wakeup network in background"); - } else if (lastPauseTime != 0) { - lastPauseTime = System.currentTimeMillis(); - FileLog.e("tmessages", "reset sleep timeout"); - } + resumeNetworkInternal(); } }); } @@ -230,26 +257,39 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection. }); } - public static void resetLastPauseTime() { - if (appPaused) { - return; - } - FileLog.e("tmessages", "reset app pause time"); - if (lastPauseTime != 0 && System.currentTimeMillis() - lastPauseTime > 5000) { - ContactsController.getInstance().checkContacts(); - } - lastPauseTime = 0; - ConnectionsManager.getInstance().applicationMovedToForeground(); + public void setAppPaused(final boolean value, final boolean byScreenState) { + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + if (!byScreenState) { + appPaused = value; + FileLog.e("tmessages", "app paused = " + value); + } + if (value) { + if (byScreenState) { + if (lastPauseTime == 0) { + lastPauseTime = System.currentTimeMillis(); + } + } else { + lastPauseTime = System.currentTimeMillis(); + } + } else { + if (appPaused) { + return; + } + FileLog.e("tmessages", "reset app pause time"); + if (lastPauseTime != 0 && System.currentTimeMillis() - lastPauseTime > 5000) { + ContactsController.getInstance().checkContacts(); + } + lastPauseTime = 0; + ConnectionsManager.getInstance().applicationMovedToForeground(); + } + } + }); } - public static void setAppPaused(boolean value) { - appPaused = value; - FileLog.e("tmessages", "app paused = " + value); - if (!appPaused) { - resetLastPauseTime(); - } else { - lastPauseTime = System.currentTimeMillis(); - } + public long getPauseTime() { + return lastPauseTime; } //================================================================================ @@ -743,15 +783,7 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection. }, null, true, RPCRequest.RPCRequestClassEnableUnauthorized | RPCRequest.RPCRequestClassGeneric | RPCRequest.RPCRequestClassWithoutLogin, dcNum == 0 ? currentDatacenterId : dcNum); } - 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) { + private TLObject wrapInLayer(TLObject object, int datacenterId, RPCRequest request) { if (object.layer() > 0) { Datacenter datacenter = datacenterWithId(datacenterId); if (datacenter == null || datacenter.lastInitVersion != currentAppVersion) { @@ -792,7 +824,7 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection. } object = invoke; } - TLRPC.invokeWithLayer12 invoke = new TLRPC.invokeWithLayer12(); + TLRPC.invokeWithLayer14 invoke = new TLRPC.invokeWithLayer14(); invoke.query = object; FileLog.d("wrap in layer", "" + object); return invoke; @@ -800,8 +832,19 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection. return object; } - public static volatile long nextCallToken = 1; - 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) { + public long performRpc(final TLObject rpc, final RPCRequest.RPCRequestDelegate completionBlock) { + return performRpc(rpc, completionBlock, null, true, RPCRequest.RPCRequestClassGeneric, DEFAULT_DATACENTER_ID); + } + + public long performRpc(final TLObject rpc, final RPCRequest.RPCRequestDelegate completionBlock, boolean requiresCompletion, int requestClass) { + return performRpc(rpc, completionBlock, null, requiresCompletion, requestClass, DEFAULT_DATACENTER_ID, true); + } + + public long performRpc(final TLObject rpc, final RPCRequest.RPCRequestDelegate completionBlock, final RPCRequest.RPCQuickAckDelegate quickAckBlock, final boolean requiresCompletion, final int requestClass, final int datacenterId) { + return performRpc(rpc, completionBlock, quickAckBlock, requiresCompletion, requestClass, datacenterId, true); + } + + public long performRpc(final TLObject rpc, final RPCRequest.RPCRequestDelegate completionBlock, final RPCRequest.RPCQuickAckDelegate quickAckBlock, final boolean requiresCompletion, final int requestClass, final int datacenterId, final boolean runQueue) { if (!UserConfig.isClientActivated() && (requestClass & RPCRequest.RPCRequestClassWithoutLogin) == 0) { FileLog.e("tmessages", "can't do request without login " + rpc); return 0; @@ -821,19 +864,14 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection. 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)) { - lastPauseTime = System.currentTimeMillis(); - nextSleepTimeout = 30000; - FileLog.e("tmessages", "wakeup by download or upload request"); + if (runQueue) { + processRequestQueue(0, 0); } - - processRequestQueue(0, 0); } }); @@ -876,7 +914,7 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection. 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); + performRpc(dropAnswer, null, false, request.flags); } } @@ -1009,8 +1047,7 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection. if ((request.flags & RPCRequest.RPCRequestClassGeneric) != 0) { connection = requestDatacenter.getGenericConnection(this); } else if ((request.flags & RPCRequest.RPCRequestClassDownloadMedia) != 0) { - int num = (request.flags & RPCRequest.RPCRequestClassDownloadMedia2) != 0 ? 1 : 0; - connection = requestDatacenter.getDownloadConnection(num, this); + connection = requestDatacenter.getDownloadConnection(this); } else if ((request.flags & RPCRequest.RPCRequestClassUploadMedia) != 0 ) { connection = requestDatacenter.getUploadConnection(this); } @@ -1026,7 +1063,7 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection. maxTimeout = 30.0f; } - boolean forceThisRequest = (request.flags & requestClass) != 0 && (_datacenterId == Integer.MIN_VALUE || requestDatacenter.datacenterId == _datacenterId); + boolean forceThisRequest = (request.flags & requestClass) != 0 && requestDatacenter.datacenterId == _datacenterId; if (request.rawRequest instanceof TLRPC.TL_get_future_salts || request.rawRequest instanceof TLRPC.TL_destroy_session) { if (request.runningMessageId != 0) { @@ -1177,8 +1214,7 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection. if ((request.flags & RPCRequest.RPCRequestClassGeneric) != 0) { connection = requestDatacenter.getGenericConnection(this); } else if ((request.flags & RPCRequest.RPCRequestClassDownloadMedia) != 0) { - int num = (request.flags & RPCRequest.RPCRequestClassDownloadMedia2) != 0 ? 1 : 0; - connection = requestDatacenter.getDownloadConnection(num, this); + connection = requestDatacenter.getDownloadConnection(this); } else if ((request.flags & RPCRequest.RPCRequestClassUploadMedia) != 0) { connection = requestDatacenter.getUploadConnection(this); } @@ -1341,29 +1377,14 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection. } } - if (datacenter.connection == null) { - datacenter.connection = new TcpConnection(datacenter.datacenterId); - datacenter.connection.delegate = this; - datacenter.connection.transportRequestClass = RPCRequest.RPCRequestClassGeneric; - } - - proceedToSendingMessages(arr, datacenter.connection, hasSendMessage); + proceedToSendingMessages(arr, datacenter.getGenericConnection(this), hasSendMessage); } } 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, false); - } - } - } else { - ArrayList messagesIt = genericMessagesToDatacenters.get(_datacenterId); - if (messagesIt == null || messagesIt.size() == 0) { - generatePing(); - } + ArrayList messagesIt = genericMessagesToDatacenters.get(_datacenterId); + if (messagesIt == null || messagesIt.size() == 0) { + generatePing(); } } @@ -1501,7 +1522,7 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection. } } - connection.sendData(null, transportData, reportAck); + connection.sendData(transportData, true, reportAck); } else { FileLog.e("tmessages", "***** Transport data is nil"); } @@ -1527,12 +1548,12 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection. TLRPC.TL_protoMessage message = networkMessage.protoMessage; if (BuildVars.DEBUG_VERSION) { - if (message.body instanceof TLRPC.invokeWithLayer12) { - FileLog.d("tmessages", connection.getSissionId() + ":DC" + datacenter.datacenterId + "> Send message (" + message.seqno + ", " + message.msg_id + "): " + ((TLRPC.invokeWithLayer12)message.body).query); + if (message.body instanceof TLRPC.invokeWithLayer14) { + FileLog.d("tmessages", connection.getSissionId() + ":DC" + datacenter.datacenterId + "> Send message (" + message.seqno + ", " + message.msg_id + "): " + ((TLRPC.invokeWithLayer14)message.body).query); } else if (message.body instanceof TLRPC.initConnection) { TLRPC.initConnection r = (TLRPC.initConnection)message.body; - if (r.query instanceof TLRPC.invokeWithLayer12) { - FileLog.d("tmessages", connection.getSissionId() + ":DC" + datacenter.datacenterId + "> Send message (" + message.seqno + ", " + message.msg_id + "): " + ((TLRPC.invokeWithLayer12)r.query).query); + if (r.query instanceof TLRPC.invokeWithLayer14) { + FileLog.d("tmessages", connection.getSissionId() + ":DC" + datacenter.datacenterId + "> Send message (" + message.seqno + ", " + message.msg_id + "): " + ((TLRPC.invokeWithLayer14)r.query).query); } else { FileLog.d("tmessages", connection.getSissionId() + ":DC" + datacenter.datacenterId + "> Send message (" + message.seqno + ", " + message.msg_id + "): " + r.query); } @@ -1567,12 +1588,12 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection. TLRPC.TL_protoMessage message = networkMessage.protoMessage; containerMessages.add(message); if (BuildVars.DEBUG_VERSION) { - if (message.body instanceof TLRPC.invokeWithLayer12) { - FileLog.d("tmessages", connection.getSissionId() + ":DC" + datacenter.datacenterId + "> Send message (" + message.seqno + ", " + message.msg_id + "): " + ((TLRPC.invokeWithLayer12)message.body).query); + if (message.body instanceof TLRPC.invokeWithLayer14) { + FileLog.d("tmessages", connection.getSissionId() + ":DC" + datacenter.datacenterId + "> Send message (" + message.seqno + ", " + message.msg_id + "): " + ((TLRPC.invokeWithLayer14)message.body).query); } else if (message.body instanceof TLRPC.initConnection) { TLRPC.initConnection r = (TLRPC.initConnection)message.body; - if (r.query instanceof TLRPC.invokeWithLayer12) { - FileLog.d("tmessages", connection.getSissionId() + ":DC" + datacenter.datacenterId + "> Send message (" + message.seqno + ", " + message.msg_id + "): " + ((TLRPC.invokeWithLayer12)r.query).query); + if (r.query instanceof TLRPC.invokeWithLayer14) { + FileLog.d("tmessages", connection.getSissionId() + ":DC" + datacenter.datacenterId + "> Send message (" + message.seqno + ", " + message.msg_id + "): " + ((TLRPC.invokeWithLayer14)r.query).query); } else { FileLog.d("tmessages", connection.getSissionId() + ":DC" + datacenter.datacenterId + "> Send message (" + message.seqno + ", " + message.msg_id + "): " + r.query); } @@ -1625,13 +1646,14 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection. ByteBufferDesc dataForEncryption = BuffersStorage.getInstance().getFreeBuffer(innerOs.limit() + zeroCount); dataForEncryption.writeRaw(innerOs); BuffersStorage.getInstance().reuseFreeBuffer(innerOs); - byte[] b = new byte[1]; - for (int a = 0; a < zeroCount; a++) { + + if (zeroCount != 0) { + byte[] b = new byte[zeroCount]; Utilities.random.nextBytes(b); - dataForEncryption.writeByte(b[0]); + dataForEncryption.writeRaw(b); } - Utilities.aesIgeEncryption2(dataForEncryption.buffer, keyData.aesKey, keyData.aesIv, true, false, dataForEncryption.limit()); + Utilities.aesIgeEncryption(dataForEncryption.buffer, keyData.aesKey, keyData.aesIv, true, false, 0, dataForEncryption.limit()); ByteBufferDesc data = BuffersStorage.getInstance().getFreeBuffer(8 + messageKey.length + dataForEncryption.limit()); data.writeInt64(datacenter.authKeyId); @@ -1645,18 +1667,24 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection. void refillSaltSet(final Datacenter datacenter) { for (RPCRequest request : requestQueue) { if (request.rawRequest instanceof TLRPC.TL_get_future_salts) { - return; + Datacenter requestDatacenter = datacenterWithId(request.runningDatacenterId); + if (requestDatacenter.datacenterId == datacenter.datacenterId) { + return; + } } } for (RPCRequest request : runningRequests) { if (request.rawRequest instanceof TLRPC.TL_get_future_salts) { - return; + Datacenter requestDatacenter = datacenterWithId(request.runningDatacenterId); + if (requestDatacenter.datacenterId == datacenter.datacenterId) { + return; + } } } TLRPC.TL_get_future_salts getFutureSalts = new TLRPC.TL_get_future_salts(); - getFutureSalts.num = 64; + getFutureSalts.num = 32; performRpc(getFutureSalts, new RPCRequest.RPCRequestDelegate() { @Override @@ -1759,7 +1787,7 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection. } registeringForPush = false; } - }, null, true, RPCRequest.RPCRequestClassGeneric); + }, true, RPCRequest.RPCRequestClassGeneric); } } @@ -1860,6 +1888,7 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection. pingIdToDate.remove(pid); } } else { + FileLog.e("tmessages", "received push ping"); sendingPushPing = false; } } else if (message instanceof TLRPC.TL_futuresalts) { @@ -2038,6 +2067,12 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection. isError = true; request.completionBlock.run(null, implicitError != null ? implicitError : (TLRPC.TL_error) resultContainer.result); } else { + if (resultContainer.result instanceof TLRPC.updates_Difference) { + pushMessagesReceived = true; + if (wakeLock.isHeld()) { + wakeLock.release(); + } + } request.completionBlock.run(resultContainer.result, null); } } @@ -2195,8 +2230,18 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection. } else if (message instanceof TLRPC.Updates) { if ((connection.transportRequestClass & RPCRequest.RPCRequestClassPush) != 0) { FileLog.e("tmessages", "received internal push"); - resumeNetworkMaybe(); + if (paused) { + pushMessagesReceived = false; + } + if (!wakeLock.isHeld()) { + wakeLock.acquire(20000); + } + resumeNetworkInternal(); } else { + pushMessagesReceived = true; + if (wakeLock.isHeld()) { + wakeLock.release(); + } MessagesController.getInstance().processUpdates((TLRPC.Updates) message, false); } } else { @@ -2255,156 +2300,18 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection. ByteBufferDesc transportData = generatePingData(connection); if (transportData != null) { if (push) { + FileLog.e("tmessages", "send push ping"); sendingPushPing = true; } - connection.sendData(null, transportData, false); + connection.sendData(transportData, true, false); } } } - 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); - long key = keyIdData.readInt64(); - if (key == 0) { - return -1; - } else { - if (datacenter.authKeyId == 0 || key != 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, 0); - - if (messageData == null) { - return -1; - } - - SerializedData messageIs = new SerializedData(messageData); - long messageServerSalt = messageIs.readInt64(); - long messageSessionId = messageIs.readInt64(); - - if (messageSessionId != connection.getSissionId()) { - FileLog.e("tmessages", String.format("***** Error: invalid message session ID (%d instead of %d)", messageSessionId, connection.getSissionId())); - 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) { @@ -2440,7 +2347,7 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection. }); } else if ((connection.transportRequestClass & RPCRequest.RPCRequestClassPush) != 0) { sendingPushPing = false; - lastPushPingTime = System.currentTimeMillis() - 60000 * 3 + 5000; + lastPushPingTime = System.currentTimeMillis() - 60000 * 3 + 4000; } } @@ -2450,10 +2357,11 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection. if (datacenter.authKey != null) { if ((connection.transportRequestClass & RPCRequest.RPCRequestClassPush) != 0) { sendingPushPing = false; - lastPushPingTime = System.currentTimeMillis() - 60000 * 3 + 10000; + lastPushPingTime = System.currentTimeMillis() - 60000 * 3 + 4000; } else { - if (paused && connection.getDatacenterId() == currentDatacenterId && (connection.transportRequestClass & RPCRequest.RPCRequestClassGeneric) != 0) { - resumeNetworkMaybe(); + if (paused && lastPauseTime != 0) { + lastPauseTime = System.currentTimeMillis(); + nextSleepTimeout = 30000; } processRequestQueue(connection.transportRequestClass, connection.getDatacenterId()); } @@ -2541,11 +2449,8 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection. byte[] messageKey = data.readData(16); MessageKeyData keyData = Utilities.generateMessageKeyData(datacenter.authKey, messageKey, true); - data.compact(); - data.limit(data.position()); - data.position(0); - Utilities.aesIgeEncryption2(data.buffer, keyData.aesKey, keyData.aesIv, false, false, length - 24); + Utilities.aesIgeEncryption(data.buffer, keyData.aesKey, keyData.aesIv, false, false, data.position(), length - 24); long messageServerSalt = data.readInt64(); long messageSessionId = data.readInt64(); @@ -2570,14 +2475,12 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection. connection.addMessageToConfirm(messageId); } - byte[] realMessageKeyFull = Utilities.computeSHA1(data.buffer, 0, Math.min(messageLength + 32, data.limit())); + byte[] realMessageKeyFull = Utilities.computeSHA1(data.buffer, 24, Math.min(messageLength + 32 + 24, data.limit())); if (realMessageKeyFull == null) { return; } - byte[] realMessageKey = new byte[16]; - System.arraycopy(realMessageKeyFull, realMessageKeyFull.length - 16, realMessageKey, 0, 16); - if (!Arrays.equals(messageKey, realMessageKey)) { + if (!Utilities.arraysEquals(messageKey, 0, realMessageKeyFull, realMessageKeyFull.length - 16)) { FileLog.e("tmessages", "***** Error: invalid message key"); connection.suspendConnection(true); connection.connect(); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/Datacenter.java b/TMessagesProj/src/main/java/org/telegram/messenger/Datacenter.java index 43fa8428a..4c1914128 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/Datacenter.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/Datacenter.java @@ -35,7 +35,7 @@ public class Datacenter { private volatile int currentAddressNum = 0; public TcpConnection connection; - private ArrayList downloadConnections = new ArrayList(); + private TcpConnection downloadConnection; private TcpConnection uploadConnection; public TcpConnection pushConnection; @@ -327,7 +327,7 @@ public class Datacenter { if (uploadConnection != null) { uploadConnection.suspendConnection(true); } - for (TcpConnection downloadConnection : downloadConnections) { + if (downloadConnection != null) { downloadConnection.suspendConnection(true); } } @@ -339,7 +339,7 @@ public class Datacenter { if (uploadConnection != null) { sessions.add(uploadConnection.getSissionId()); } - for (TcpConnection downloadConnection : downloadConnections) { + if (downloadConnection != null) { sessions.add(downloadConnection.getSissionId()); } } @@ -351,26 +351,21 @@ public class Datacenter { if (uploadConnection != null) { uploadConnection.recreateSession(); } - for (TcpConnection downloadConnection : downloadConnections) { + if (downloadConnection != null) { downloadConnection.recreateSession(); } } - public TcpConnection getDownloadConnection(int num, TcpConnection.TcpConnectionDelegate delegate) { - if (num >= 0 && authKey != null) { - TcpConnection downloadConnection = null; - if (num < downloadConnections.size()) { - downloadConnection = downloadConnections.get(num); - } else { + public TcpConnection getDownloadConnection(TcpConnection.TcpConnectionDelegate delegate) { + if (authKey != null) { + if (downloadConnection == null) { downloadConnection = new TcpConnection(datacenterId); downloadConnection.delegate = delegate; downloadConnection.transportRequestClass = RPCRequest.RPCRequestClassDownloadMedia; - downloadConnections.add(downloadConnection); } downloadConnection.connect(); - return downloadConnection; } - return null; + return downloadConnection; } public TcpConnection getUploadConnection(TcpConnection.TcpConnectionDelegate delegate) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ExportAuthorizationAction.java b/TMessagesProj/src/main/java/org/telegram/messenger/ExportAuthorizationAction.java index be79765a3..51367696d 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ExportAuthorizationAction.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ExportAuthorizationAction.java @@ -54,7 +54,7 @@ public class ExportAuthorizationAction extends Action { } } } - }, null, true, RPCRequest.RPCRequestClassGeneric); + }); } void beginImport() { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoadOperation.java b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoadOperation.java index cd577fbae..f436b1161 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoadOperation.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoadOperation.java @@ -10,9 +10,9 @@ package org.telegram.messenger; import android.graphics.Bitmap; import android.graphics.BitmapFactory; -import android.os.Build; import android.provider.MediaStore; +import org.telegram.android.AndroidUtilities; import org.telegram.ui.ApplicationLoader; import java.io.RandomAccessFile; @@ -22,10 +22,19 @@ import java.io.FileInputStream; import java.io.InputStream; import java.net.URLConnection; import java.nio.channels.FileChannel; +import java.util.ArrayList; import java.util.Scanner; public class FileLoadOperation { - private int downloadChunkSize = 1024 * 256; + + private static class RequestInfo { + private long requestToken = 0; + private int offset = 0; + private TLRPC.TL_upload_file response = null; + } + + private final static int downloadChunkSize = 1024 * 32; + private final static int maxDownloadRequests = 3; public int datacenter_id; public TLRPC.InputFileLocation location; @@ -37,14 +46,10 @@ public class FileLoadOperation { public String filter; private byte[] key; private byte[] iv; - private long requestToken = 0; - private long requestToken2 = 0; - private int requestProgress = 0; - private int requestProgress2 = 0; + private int nextDownloadOffset = 0; - private TLRPC.TL_upload_file delayedRes = null; - private int delayedResOffset = 0; - private int delayedResTokenNum = 0; + private ArrayList requestInfos = new ArrayList(maxDownloadRequests); + private ArrayList delayedRequestInfos = new ArrayList(maxDownloadRequests - 1); private File cacheFileTemp; private File cacheFileFinal; @@ -56,7 +61,7 @@ public class FileLoadOperation { public boolean needBitmapCreate = true; private InputStream httpConnectionStream; private RandomAccessFile fileOutputStream; - RandomAccessFile fiv; + private RandomAccessFile fiv; public static interface FileLoadOperationDelegate { public abstract void didFinishLoadingFile(FileLoadOperation operation); @@ -214,7 +219,7 @@ public class FileLoadOperation { if (isLocalFile) { cacheFileFinal = new File(fileNameFinal); } else { - cacheFileFinal = new File(Utilities.getCacheDir(), fileNameFinal); + cacheFileFinal = new File(AndroidUtilities.getCacheDir(), fileNameFinal); } final boolean dontDelete = isLocalFile; final Long mediaIdFinal = mediaId; @@ -245,8 +250,8 @@ public class FileLoadOperation { float h_filter = 0; if (filter != null) { String args[] = filter.split("_"); - w_filter = Float.parseFloat(args[0]) * Utilities.density; - h_filter = Float.parseFloat(args[1]) * Utilities.density; + w_filter = Float.parseFloat(args[0]) * AndroidUtilities.density; + h_filter = Float.parseFloat(args[1]) * AndroidUtilities.density; opts.inJustDecodeBounds = true; if (mediaIdFinal != null) { @@ -289,11 +294,9 @@ public class FileLoadOperation { float bitmapH = image.getHeight(); if (bitmapW != w_filter && bitmapW > w_filter) { float scaleFactor = bitmapW / w_filter; - Bitmap scaledBitmap = Bitmap.createScaledBitmap(image, (int)w_filter, (int)(bitmapH / scaleFactor), false); + Bitmap scaledBitmap = Bitmap.createScaledBitmap(image, (int)w_filter, (int)(bitmapH / scaleFactor), true); if (image != scaledBitmap) { - if (Build.VERSION.SDK_INT < 11) { - image.recycle(); - } + image.recycle(); image = scaledBitmap; } } @@ -339,13 +342,13 @@ public class FileLoadOperation { }); return; } - cacheFileTemp = new File(Utilities.getCacheDir(), fileNameTemp); + cacheFileTemp = new File(AndroidUtilities.getCacheDir(), fileNameTemp); if (cacheFileTemp.exists()) { downloadedBytes = (int)cacheFileTemp.length(); nextDownloadOffset = downloadedBytes = downloadedBytes / 1024 * 1024; } if (fileNameIv != null) { - cacheIvTemp = new File(Utilities.getCacheDir(), fileNameIv); + cacheIvTemp = new File(AndroidUtilities.getCacheDir(), fileNameIv); try { fiv = new RandomAccessFile(cacheIvTemp, "rws"); long len = cacheIvTemp.length(); @@ -383,27 +386,44 @@ public class FileLoadOperation { if (httpUrl != null) { startDownloadHTTPRequest(); } else { - if (totalBytesCount >= 1024 * 1024) { - downloadChunkSize = 1024 * 256; - } else { - downloadChunkSize = 1024 * 32; - } - startDownloadRequest(); + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + if (totalBytesCount != 0 && downloadedBytes == totalBytesCount) { + try { + onFinishLoadingFile(); + } catch (Exception e) { + delegate.didFailedLoadingFile(FileLoadOperation.this); + } + } else { + startDownloadRequest(); + } + } + }); + } } } public void cancel() { - if (state != 1) { - return; - } - state = 2; - cleanup(); - if (httpUrl == null) { - ConnectionsManager.getInstance().cancelRpc(requestToken, true); - ConnectionsManager.getInstance().cancelRpc(requestToken2, true); - } - delegate.didFailedLoadingFile(FileLoadOperation.this); + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + if (state != 1) { + return; + } + state = 2; + cleanup(); + if (httpUrl == null) { + for (RequestInfo requestInfo : requestInfos) { + if (requestInfo.requestToken != 0) { + ConnectionsManager.getInstance().cancelRpc(requestInfo.requestToken, true, true); + } + } + } + delegate.didFailedLoadingFile(FileLoadOperation.this); + } + }); } private void cleanup() { @@ -435,11 +455,12 @@ public class FileLoadOperation { } catch (Exception e) { FileLog.e("tmessages", e); } - - if (delayedRes != null) { - delayedRes.disableFree = false; - delayedRes.freeResources(); - delayedRes = null; + for (RequestInfo requestInfo : delayedRequestInfos) { + if (requestInfo.response != null) { + requestInfo.response.disableFree = false; + requestInfo.response.freeResources(); + requestInfo.response = null; + } } } } @@ -454,7 +475,6 @@ public class FileLoadOperation { cacheIvTemp.delete(); } final boolean renamed = cacheFileTemp.renameTo(cacheFileFinal); - if (needBitmapCreate) { FileLoader.cacheOutQueue.postRunnable(new Runnable() { @Override @@ -476,8 +496,8 @@ public class FileLoadOperation { float h_filter; if (filter != null) { String args[] = filter.split("_"); - w_filter = Float.parseFloat(args[0]) * Utilities.density; - h_filter = Float.parseFloat(args[1]) * Utilities.density; + w_filter = Float.parseFloat(args[0]) * AndroidUtilities.density; + h_filter = Float.parseFloat(args[1]) * AndroidUtilities.density; opts.inJustDecodeBounds = true; BitmapFactory.decodeFile(cacheFileFinal.getAbsolutePath(), opts); @@ -514,11 +534,9 @@ public class FileLoadOperation { float bitmapH = image.getHeight(); if (bitmapW != w_filter && bitmapW > w_filter) { float scaleFactor = bitmapW / w_filter; - Bitmap scaledBitmap = Bitmap.createScaledBitmap(image, (int) w_filter, (int) (bitmapH / scaleFactor), false); + Bitmap scaledBitmap = Bitmap.createScaledBitmap(image, (int) w_filter, (int) (bitmapH / scaleFactor), true); if (image != scaledBitmap) { - if (Build.VERSION.SDK_INT < 11) { - image.recycle(); - } + image.recycle(); image = scaledBitmap; } } @@ -612,57 +630,49 @@ public class FileLoadOperation { } } - private void processRequestResult(TLRPC.TL_upload_file res, TLRPC.TL_error error, int dowloadOffset, int tokenNum) { + private void processRequestResult(RequestInfo requestInfo, TLRPC.TL_error error) { + requestInfos.remove(requestInfo); if (error == null) { try { - if (downloadedBytes != dowloadOffset) { - if (delayedRes != null) { - FileLog.e("tmessages", "something went wrong!"); - } - delayedRes = res; - delayedRes.disableFree = true; - delayedResOffset = dowloadOffset; - delayedResTokenNum = tokenNum; + if (downloadedBytes != requestInfo.offset) { + delayedRequestInfos.add(requestInfo); + requestInfo.response.disableFree = true; return; - } else { - if (tokenNum == 0) { - requestToken = 0; - } else if (tokenNum == 1) { - requestToken2 = 0; - } } - if (res.bytes.limit() == 0) { + if (requestInfo.response.bytes.limit() == 0) { onFinishLoadingFile(); return; } if (key != null) { - Utilities.aesIgeEncryption2(res.bytes.buffer, key, iv, false, true, res.bytes.limit()); + Utilities.aesIgeEncryption(requestInfo.response.bytes.buffer, key, iv, false, true, 0, requestInfo.response.bytes.limit()); } if (fileOutputStream != null) { FileChannel channel = fileOutputStream.getChannel(); - channel.write(res.bytes.buffer); + channel.write(requestInfo.response.bytes.buffer); } if (fiv != null) { fiv.seek(0); fiv.write(iv); } - downloadedBytes += res.bytes.limit(); + downloadedBytes += requestInfo.response.bytes.limit(); if (totalBytesCount > 0 && state == 1) { delegate.didChangedLoadProgress(FileLoadOperation.this, Math.min(1.0f, (float)downloadedBytes / (float)totalBytesCount)); } - if(delayedRes != null && res != delayedRes) { - TLRPC.TL_upload_file temp = delayedRes; - processRequestResult(temp, null, delayedResOffset, delayedResTokenNum); - if (delayedRes != null) { - delayedRes.disableFree = false; - delayedRes.freeResources(); - delayedRes = null; + for (int a = 0; a < delayedRequestInfos.size(); a++) { + RequestInfo delayedRequestInfo = delayedRequestInfos.get(a); + if (downloadedBytes == delayedRequestInfo.offset) { + delayedRequestInfos.remove(a); + processRequestResult(delayedRequestInfo, null); + delayedRequestInfo.response.disableFree = false; + delayedRequestInfo.response.freeResources(); + delayedRequestInfo = null; + break; } } - if (downloadedBytes % downloadChunkSize == 0 || totalBytesCount > 0 && totalBytesCount != downloadedBytes) { + if (downloadedBytes % downloadChunkSize == 0 || totalBytesCount > 0 && totalBytesCount > downloadedBytes) { startDownloadRequest(); } else { onFinishLoadingFile(); @@ -714,69 +724,36 @@ public class FileLoadOperation { } } - private void processRequestProgress() { - delegate.didChangedLoadProgress(FileLoadOperation.this, Math.min(1.0f, (float) (downloadedBytes + requestProgress + requestProgress2) / (float) totalBytesCount)); - } - private void startDownloadRequest() { - if (state != 1) { + if (state != 1 || totalBytesCount > 0 && nextDownloadOffset >= totalBytesCount || requestInfos.size() + delayedRequestInfos.size() >= maxDownloadRequests) { return; } - if (requestToken == 0) { - requestProgress = 0; - if (totalBytesCount > 0 && nextDownloadOffset >= totalBytesCount) { - return; - } - final TLRPC.TL_upload_getFile req = new TLRPC.TL_upload_getFile(); - req.location = location; - req.offset = nextDownloadOffset; - req.limit = downloadChunkSize; - nextDownloadOffset += downloadChunkSize; - final long time = System.currentTimeMillis(); - requestToken = ConnectionsManager.getInstance().performRpc(req, new RPCRequest.RPCRequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - processRequestResult((TLRPC.TL_upload_file) response, error, req.offset, 0); - } - }, new RPCRequest.RPCProgressDelegate() { - @Override - public void progress(int length, int progress) { - if (state == 1) { - requestProgress = progress; - if (totalBytesCount == -1) { - delegate.didChangedLoadProgress(FileLoadOperation.this, Math.min(1.0f, (float) (progress) / (float) length)); - } else if (totalBytesCount > 0) { - processRequestProgress(); - } - } - } - }, null, true, RPCRequest.RPCRequestClassDownloadMedia, datacenter_id); + int count = 1; + if (totalBytesCount > 0) { + count = Math.max(0, maxDownloadRequests - requestInfos.size() - delayedRequestInfos.size()); } - if (totalBytesCount > 0 && requestToken2 == 0) { - requestProgress2 = 0; + + for (int a = 0; a < count; a++) { if (totalBytesCount > 0 && nextDownloadOffset >= totalBytesCount) { - return; + break; } - final long time = System.currentTimeMillis(); - final TLRPC.TL_upload_getFile req = new TLRPC.TL_upload_getFile(); + boolean isLast = totalBytesCount <= 0 || a == count - 1 || totalBytesCount > 0 && nextDownloadOffset + downloadChunkSize >= totalBytesCount; + TLRPC.TL_upload_getFile req = new TLRPC.TL_upload_getFile(); req.location = location; req.offset = nextDownloadOffset; req.limit = downloadChunkSize; nextDownloadOffset += downloadChunkSize; - requestToken2 = ConnectionsManager.getInstance().performRpc(req, new RPCRequest.RPCRequestDelegate() { + + final RequestInfo requestInfo = new RequestInfo(); + requestInfos.add(requestInfo); + requestInfo.offset = req.offset; + requestInfo.requestToken = ConnectionsManager.getInstance().performRpc(req, new RPCRequest.RPCRequestDelegate() { @Override public void run(TLObject response, TLRPC.TL_error error) { - processRequestResult((TLRPC.TL_upload_file) response, error, req.offset, 1); + requestInfo.response = (TLRPC.TL_upload_file) response; + processRequestResult(requestInfo, error); } - }, new RPCRequest.RPCProgressDelegate() { - @Override - public void progress(int length, int progress) { - if (state == 1) { - requestProgress2 = progress; - processRequestProgress(); - } - } - }, null, true, RPCRequest.RPCRequestClassDownloadMedia | RPCRequest.RPCRequestClassDownloadMedia2, datacenter_id); + }, null, true, RPCRequest.RPCRequestClassDownloadMedia, datacenter_id, isLast); } } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java index 9194bb178..9019f118d 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java @@ -18,6 +18,7 @@ import android.net.Uri; import android.os.Build; import android.os.ParcelFileDescriptor; +import org.telegram.android.AndroidUtilities; import org.telegram.objects.MessageObject; import org.telegram.ui.ApplicationLoader; import org.telegram.ui.Views.ImageReceiver; @@ -291,10 +292,8 @@ public class FileLoader { if (runtimeHack != null) { runtimeHack.trackAlloc(oldBitmap.getRowBytes() * oldBitmap.getHeight()); } - if (Build.VERSION.SDK_INT < 11) { - if (!oldBitmap.isRecycled()) { - oldBitmap.recycle(); - } + if (!oldBitmap.isRecycled()) { + oldBitmap.recycle(); } } } @@ -466,6 +465,7 @@ public class FileLoader { } FileLoadOperation operation = loadOperationPaths.get(fileName); if (operation != null) { + loadOperationPaths.remove(fileName); if (audio != null) { audioLoadOperationQueue.remove(operation); } else if (photo != null) { @@ -1119,7 +1119,7 @@ public class FileLoader { try { if (!cache) { String fileName = location.volume_id + "_" + location.local_id + ".jpg"; - final File cacheFile = new File(Utilities.getCacheDir(), fileName); + final File cacheFile = new File(AndroidUtilities.getCacheDir(), fileName); FileOutputStream stream = new FileOutputStream(cacheFile); scaledBitmap.compress(Bitmap.CompressFormat.JPEG, quality, stream); size.size = (int)stream.getChannel().size(); @@ -1129,10 +1129,8 @@ public class FileLoader { size.bytes = stream.toByteArray(); size.size = size.bytes.length; } - if (Build.VERSION.SDK_INT < 11) { - if (scaledBitmap != bitmap) { - scaledBitmap.recycle(); - } + if (scaledBitmap != bitmap) { + scaledBitmap.recycle(); } return size; } catch (Exception e) { diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/FileLog.java b/TMessagesProj/src/main/java/org/telegram/messenger/FileLog.java index 9ba567200..35d460d17 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/FileLog.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/FileLog.java @@ -11,6 +11,7 @@ package org.telegram.messenger; import android.net.Uri; import android.util.Log; +import org.telegram.android.FastDateFormat; import org.telegram.ui.ApplicationLoader; import java.io.File; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/FileUploadOperation.java b/TMessagesProj/src/main/java/org/telegram/messenger/FileUploadOperation.java index 87e0a1a35..7f8aaadbe 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/FileUploadOperation.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/FileUploadOperation.java @@ -31,7 +31,7 @@ public class FileUploadOperation { private byte[] key; private byte[] iv; private byte[] ivChange; - private int fingerprint; + private int fingerprint = 0; private boolean isBigFile = false; FileInputStream stream; MessageDigest mdEnc = null; @@ -57,11 +57,9 @@ public class FileUploadOperation { System.arraycopy(key, 0, arr, 0, 32); System.arraycopy(iv, 0, arr, 32, 32); byte[] digest = md.digest(arr); - byte[] fingerprintBytes = new byte[4]; for (int a = 0; a < 4; a++) { - fingerprintBytes[a] = (byte)(digest[a] ^ digest[a + 4]); + fingerprint |= ((digest[a] ^ digest[a + 4]) & 0xFF) << (a * 8); } - fingerprint = Utilities.bytesToInt(fingerprintBytes); } catch (Exception e) { FileLog.e("tmessages", e); } @@ -138,7 +136,7 @@ public class FileUploadOperation { for (int a = 0; a < toAdd; a++) { sendBuffer.writeByte(0); } - Utilities.aesIgeEncryption2(sendBuffer.buffer, key, ivChange, true, true, readed + toAdd); + Utilities.aesIgeEncryption(sendBuffer.buffer, key, ivChange, true, true, 0, readed + toAdd); } sendBuffer.rewind(); if (!isBigFile) { @@ -211,11 +209,6 @@ public class FileUploadOperation { delegate.didFailedUploadingFile(FileUploadOperation.this); } } - }, new RPCRequest.RPCProgressDelegate() { - @Override - public void progress(int length, int progress) { - - } }, null, true, RPCRequest.RPCRequestClassUploadMedia, ConnectionsManager.DEFAULT_DATACENTER_ID); } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/HandshakeAction.java b/TMessagesProj/src/main/java/org/telegram/messenger/HandshakeAction.java index e28cbbbca..d2632e96e 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/HandshakeAction.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/HandshakeAction.java @@ -12,7 +12,6 @@ import java.math.BigInteger; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.ArrayList; -import java.util.Arrays; import java.util.HashMap; import java.util.Locale; @@ -29,9 +28,9 @@ public class HandshakeAction extends Action implements TcpConnection.TcpConnecti private boolean processedPQRes; - private byte[] reqPQMsgData; - private byte[] reqDHMsgData; - private byte[] setClientDHParamsMsgData; + private ByteBufferDesc reqPQMsgData; + private ByteBufferDesc reqDHMsgData; + private ByteBufferDesc setClientDHParamsMsgData; private boolean wasDisconnect = false; private long lastOutgoingMessageId; @@ -63,9 +62,18 @@ public class HandshakeAction extends Action implements TcpConnection.TcpConnecti authKey = null; authKeyId = 0; processedPQRes = false; - reqPQMsgData = null; - reqDHMsgData = null; - setClientDHParamsMsgData = null; + if (reqPQMsgData != null) { + BuffersStorage.getInstance().reuseFreeBuffer(reqPQMsgData); + reqPQMsgData = null; + } + if (reqDHMsgData != null) { + BuffersStorage.getInstance().reuseFreeBuffer(reqDHMsgData); + reqDHMsgData = null; + } + if (setClientDHParamsMsgData != null) { + BuffersStorage.getInstance().reuseFreeBuffer(setClientDHParamsMsgData); + setClientDHParamsMsgData = null; + } if (dropConnection) { datacenter.connection.suspendConnection(true); @@ -165,23 +173,21 @@ public class HandshakeAction extends Action implements TcpConnection.TcpConnecti return messageId; } - byte[] sendMessageData(TLObject message, long messageId) { - byte[] messageData; - SerializedData innerOs = new SerializedData(); + ByteBufferDesc sendMessageData(TLObject message, long messageId) { + ByteBufferDesc innerOs = BuffersStorage.getInstance().getFreeBuffer(message.getObjectSize()); message.serializeToStream(innerOs); - messageData = innerOs.toByteArray(); + message.freeResources(); - SerializedData messageOs = new SerializedData(); + ByteBufferDesc messageOs = BuffersStorage.getInstance().getFreeBuffer(8 + 8 + 4 + innerOs.length()); messageOs.writeInt64(0); messageOs.writeInt64(messageId); - messageOs.writeInt32(messageData.length); - messageOs.writeRaw(messageData); + messageOs.writeInt32(innerOs.length()); + innerOs.position(0); + messageOs.writeRaw(innerOs); + BuffersStorage.getInstance().reuseFreeBuffer(innerOs); - byte[] transportData = messageOs.toByteArray(); - - datacenter.connection.sendData(transportData, null, false); - - return transportData; + datacenter.connection.sendData(messageOs, false, false); + return messageOs; } void processMessage(TLObject message, long messageId) { @@ -196,7 +202,7 @@ public class HandshakeAction extends Action implements TcpConnection.TcpConnecti processedPQRes = true; final TLRPC.TL_resPQ resPq = (TLRPC.TL_resPQ)message; - if (Arrays.equals(authNonce, resPq.nonce)) { + if (Utilities.arraysEquals(authNonce, 0, resPq.nonce, 0)) { final HashMap publicKey = selectPublicKey(resPq.server_public_key_fingerprints); if (publicKey == null) { FileLog.e("tmessages", "***** Couldn't find valid server public key"); @@ -276,7 +282,10 @@ public class HandshakeAction extends Action implements TcpConnection.TcpConnecti msgsAck.msg_ids.add(messageIdf); sendMessageData(msgsAck, generateMessageId()); - reqPQMsgData = null; + if (reqPQMsgData != null) { + BuffersStorage.getInstance().reuseFreeBuffer(reqPQMsgData); + reqPQMsgData = null; + } reqDHMsgData = sendMessageData(reqDH, generateMessageId()); } }); @@ -322,33 +331,33 @@ public class HandshakeAction extends Action implements TcpConnection.TcpConnecti System.arraycopy(authNewNonce, 0, newNonce0_4, 0, 4); tmpAesIv.writeRaw(newNonce0_4); - byte[] answerWithHash = Utilities.aesIgeEncryption(serverDhParams.encrypted_answer, tmpAesKey.toByteArray(), tmpAesIv.toByteArray(), false, false, 0); - byte[] answerHash = new byte[20]; - System.arraycopy(answerWithHash, 0, answerHash, 0, 20); + ByteBufferDesc answerWithHash = BuffersStorage.getInstance().getFreeBuffer(serverDhParams.encrypted_answer.length); + answerWithHash.writeRaw(serverDhParams.encrypted_answer); + answerWithHash.position(0); + + Utilities.aesIgeEncryption(answerWithHash.buffer, tmpAesKey.toByteArray(), tmpAesIv.toByteArray(), false, false, 0, serverDhParams.encrypted_answer.length); + byte[] answerHash = new byte[20]; + answerWithHash.readRaw(answerHash); - byte[] answerData = new byte[answerWithHash.length - 20]; - System.arraycopy(answerWithHash, 20, answerData, 0, answerWithHash.length - 20); boolean hashVerified = false; for (int i = 0; i < 16; i++) { - byte[] computedAnswerHash = Utilities.computeSHA1(answerData); - if (Arrays.equals(computedAnswerHash, answerHash)) { + byte[] computedAnswerHash = Utilities.computeSHA1(answerWithHash.buffer, 20, answerWithHash.limit() - i); + if (Utilities.arraysEquals(computedAnswerHash, 0, answerHash, 0)) { hashVerified = true; break; } - byte[] answerData2 = new byte[answerData.length - 1]; - System.arraycopy(answerData, 0, answerData2, 0, answerData.length - 1); - answerData = answerData2; } if (!hashVerified) { FileLog.e("tmessages", "***** Couldn't decode DH params"); beginHandshake(false); + BuffersStorage.getInstance().reuseFreeBuffer(answerWithHash); return; } - SerializedData answerIs = new SerializedData(answerData); - int constructor = answerIs.readInt32(); - TLRPC.TL_server_DH_inner_data dhInnerData = (TLRPC.TL_server_DH_inner_data)TLClassStore.Instance().TLdeserialize(answerIs, constructor); + int constructor = answerWithHash.readInt32(); + TLRPC.TL_server_DH_inner_data dhInnerData = (TLRPC.TL_server_DH_inner_data)TLClassStore.Instance().TLdeserialize(answerWithHash, constructor); + BuffersStorage.getInstance().reuseFreeBuffer(answerWithHash); if (!(dhInnerData instanceof TLRPC.TL_server_DH_inner_data)) { FileLog.e("tmessages", "***** Couldn't parse decoded DH params"); @@ -360,12 +369,12 @@ public class HandshakeAction extends Action implements TcpConnection.TcpConnecti throw new RuntimeException("bad prime"); } - if (!Arrays.equals(authNonce, dhInnerData.nonce)) { + if (!Utilities.arraysEquals(authNonce, 0, dhInnerData.nonce, 0)) { FileLog.e("tmessages", "***** Invalid DH nonce"); beginHandshake(false); return; } - if (!Arrays.equals(authServerNonce, dhInnerData.server_nonce)) { + if (!Utilities.arraysEquals(authServerNonce, 0, dhInnerData.server_nonce, 0)) { FileLog.e("tmessages", "***** Invalid DH server nonce"); beginHandshake(false); return; @@ -427,50 +436,66 @@ public class HandshakeAction extends Action implements TcpConnection.TcpConnecti clientInnerData.server_nonce = authServerNonce; clientInnerData.g_b = g_b.toByteArray(); clientInnerData.retry_id = 0; - SerializedData os = new SerializedData(); - clientInnerData.serializeToStream(os); - byte[] clientInnerDataBytes = os.toByteArray(); - SerializedData clientDataWithHash = new SerializedData(); - clientDataWithHash.writeRaw(Utilities.computeSHA1(clientInnerDataBytes)); - clientDataWithHash.writeRaw(clientInnerDataBytes); - byte[] bb = new byte[1]; - while (clientDataWithHash.length() % 16 != 0) { + ByteBufferDesc os = BuffersStorage.getInstance().getFreeBuffer(clientInnerData.getObjectSize()); + clientInnerData.serializeToStream(os); + + int len = os.length() + 20; + int extraLen = len % 16 != 0 ? 16 - len % 16 : 0; + ByteBufferDesc clientDataWithHash = BuffersStorage.getInstance().getFreeBuffer(len + extraLen); + clientDataWithHash.writeRaw(Utilities.computeSHA1(os.buffer)); + os.position(0); + clientDataWithHash.writeRaw(os); + if (extraLen != 0) { + byte[] bb = new byte[extraLen]; Utilities.random.nextBytes(bb); - clientDataWithHash.writeByte(bb[0]); + clientDataWithHash.writeRaw(bb); } + BuffersStorage.getInstance().reuseFreeBuffer(os); TLRPC.TL_set_client_DH_params setClientDhParams = new TLRPC.TL_set_client_DH_params(); setClientDhParams.nonce = authNonce; setClientDhParams.server_nonce = authServerNonce; - setClientDhParams.encrypted_data = Utilities.aesIgeEncryption(clientDataWithHash.toByteArray(), tmpAesKey.toByteArray(), tmpAesIv.toByteArray(), true, false, 0); + Utilities.aesIgeEncryption(clientDataWithHash.buffer, tmpAesKey.toByteArray(), tmpAesIv.toByteArray(), true, false, 0, clientDataWithHash.length()); + setClientDhParams.encrypted_data = clientDataWithHash; TLRPC.TL_msgs_ack msgsAck = new TLRPC.TL_msgs_ack(); msgsAck.msg_ids = new ArrayList(); msgsAck.msg_ids.add(messageId); sendMessageData(msgsAck, generateMessageId()); - reqDHMsgData = null; + if (reqDHMsgData != null) { + BuffersStorage.getInstance().reuseFreeBuffer(reqDHMsgData); + reqDHMsgData = null; + } setClientDHParamsMsgData = sendMessageData(setClientDhParams, generateMessageId()); } else { FileLog.e("tmessages", "***** Couldn't set DH params"); beginHandshake(false); } } else if (message instanceof TLRPC.Set_client_DH_params_answer) { + if (setClientDHParamsMsgData != null) { + BuffersStorage.getInstance().reuseFreeBuffer(setClientDHParamsMsgData); + setClientDHParamsMsgData = null; + } + TLRPC.Set_client_DH_params_answer dhAnswer = (TLRPC.Set_client_DH_params_answer)message; - if (!Arrays.equals(authNonce, dhAnswer.nonce)) { + if (!Utilities.arraysEquals(authNonce, 0, dhAnswer.nonce, 0)) { FileLog.e("tmessages", "***** Invalid DH answer nonce"); beginHandshake(false); return; } - if (!Arrays.equals(authServerNonce, dhAnswer.server_nonce)) { + if (!Utilities.arraysEquals(authServerNonce, 0, dhAnswer.server_nonce, 0)) { FileLog.e("tmessages", "***** Invalid DH answer server nonce"); beginHandshake(false); return; } - reqDHMsgData = null; + if (reqDHMsgData != null) { + BuffersStorage.getInstance().reuseFreeBuffer(reqDHMsgData); + reqDHMsgData = null; + } TLRPC.TL_msgs_ack msgsAck = new TLRPC.TL_msgs_ack(); msgsAck.msg_ids = new ArrayList(); @@ -507,7 +532,7 @@ public class HandshakeAction extends Action implements TcpConnection.TcpConnecti if (message instanceof TLRPC.TL_dh_gen_ok) { TLRPC.TL_dh_gen_ok dhGenOk = (TLRPC.TL_dh_gen_ok)message; - if (!Arrays.equals(newNonceHash1, dhGenOk.new_nonce_hash1)) { + if (!Utilities.arraysEquals(newNonceHash1, 0, dhGenOk.new_nonce_hash1, 0)) { FileLog.e("tmessages", "***** Invalid DH answer nonce hash 1"); beginHandshake(false); return; @@ -532,7 +557,7 @@ public class HandshakeAction extends Action implements TcpConnection.TcpConnecti }); } else if (message instanceof TLRPC.TL_dh_gen_retry) { TLRPC.TL_dh_gen_retry dhRetry = (TLRPC.TL_dh_gen_retry)message; - if (!Arrays.equals(newNonceHash2, dhRetry.new_nonce_hash2)) { + if (!Utilities.arraysEquals(newNonceHash2, 0, dhRetry.new_nonce_hash2, 0)) { FileLog.e("tmessages", "***** Invalid DH answer nonce hash 2"); beginHandshake(false); return; @@ -541,7 +566,7 @@ public class HandshakeAction extends Action implements TcpConnection.TcpConnecti beginHandshake(false); } else if (message instanceof TLRPC.TL_dh_gen_fail) { TLRPC.TL_dh_gen_fail dhFail = (TLRPC.TL_dh_gen_fail)message; - if (!Arrays.equals(newNonceHash3, dhFail.new_nonce_hash3)) { + if (!Utilities.arraysEquals(newNonceHash3, 0, dhFail.new_nonce_hash3, 0)) { FileLog.e("tmessages", "***** Invalid DH answer nonce hash 3"); beginHandshake(false); return; @@ -560,11 +585,6 @@ public class HandshakeAction extends Action implements TcpConnection.TcpConnecti } } - @Override - public void tcpConnectionProgressChanged(TcpConnection connection, long messageId, int currentSize, int length) { - - } - @Override public void tcpConnectionClosed(final TcpConnection connection) { wasDisconnect = true; @@ -582,11 +602,11 @@ public class HandshakeAction extends Action implements TcpConnection.TcpConnecti return; } if (reqPQMsgData != null) { - datacenter.connection.sendData(reqPQMsgData, null, false); + datacenter.connection.sendData(reqPQMsgData, false, false); } else if (reqDHMsgData != null) { - datacenter.connection.sendData(reqDHMsgData, null, false); + datacenter.connection.sendData(reqDHMsgData, false, false); } else if (setClientDHParamsMsgData != null) { - datacenter.connection.sendData(setClientDHParamsMsgData, null, false); + datacenter.connection.sendData(setClientDHParamsMsgData, false, false); } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/RPCRequest.java b/TMessagesProj/src/main/java/org/telegram/messenger/RPCRequest.java index ab6162aed..bd8b78988 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/RPCRequest.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/RPCRequest.java @@ -14,9 +14,6 @@ public class RPCRequest { public interface RPCRequestDelegate { void run(TLObject response, TLRPC.TL_error error); } - public interface RPCProgressDelegate { - void progress(int length, int progress); - } public interface RPCQuickAckDelegate { void quickAck(); } @@ -29,7 +26,6 @@ public class RPCRequest { public static int RPCRequestClassCanCompress = 32; public static int RPCRequestClassPush = 64; public static int RPCRequestClassWithoutLogin = 128; - public static int RPCRequestClassDownloadMedia2 = 256; static int RPCRequestClassTransportMask = (RPCRequestClassGeneric | RPCRequestClassDownloadMedia | RPCRequestClassUploadMedia); @@ -45,7 +41,6 @@ public class RPCRequest { int serializedLength; RPCRequestDelegate completionBlock; - RPCProgressDelegate progressBlock; RPCQuickAckDelegate quickAckBlock; boolean requiresCompletion; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/TLClassStore.java b/TMessagesProj/src/main/java/org/telegram/messenger/TLClassStore.java index 2e1895e5c..513417a47 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/TLClassStore.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/TLClassStore.java @@ -412,6 +412,14 @@ public class TLClassStore { classStore.put(TLRPC.TL_decryptedMessageActionFlushHistory.constructor, TLRPC.TL_decryptedMessageActionFlushHistory.class); classStore.put(TLRPC.TL_decryptedMessageActionScreenshotMessages.constructor, TLRPC.TL_decryptedMessageActionScreenshotMessages.class); classStore.put(TLRPC.TL_messageEcryptedAction.constructor, TLRPC.TL_messageEcryptedAction.class); + classStore.put(TLRPC.TL_decryptedMessageActionNotifyLayer.constructor, TLRPC.TL_decryptedMessageActionNotifyLayer.class); + classStore.put(TLRPC.TL_decryptedMessageActionReadMessages.constructor, TLRPC.TL_decryptedMessageActionReadMessages.class); + classStore.put(TLRPC.TL_updateNotifySettings.constructor, TLRPC.TL_updateNotifySettings.class); + classStore.put(TLRPC.TL_updateUserBlocked.constructor, TLRPC.TL_updateUserBlocked.class); + classStore.put(TLRPC.TL_notifyAll.constructor, TLRPC.TL_notifyAll.class); + classStore.put(TLRPC.TL_notifyChats.constructor, TLRPC.TL_notifyChats.class); + classStore.put(TLRPC.TL_notifyUsers.constructor, TLRPC.TL_notifyUsers.class); + classStore.put(TLRPC.TL_notifyPeer.constructor, TLRPC.TL_notifyPeer.class); classStore.put(TLRPC.TL_msg_container.constructor, TLRPC.TL_msg_container.class); classStore.put(TLRPC.TL_fileEncryptedLocation.constructor, TLRPC.TL_fileEncryptedLocation.class); @@ -427,6 +435,10 @@ public class TLClassStore { classStore.put(TLRPC.TL_messageActionLoginUnknownLocation.constructor, TLRPC.TL_messageActionLoginUnknownLocation.class); classStore.put(TLRPC.TL_encryptedChat_old.constructor, TLRPC.TL_encryptedChat_old.class); classStore.put(TLRPC.TL_encryptedChatRequested_old.constructor, TLRPC.TL_encryptedChatRequested_old.class); + classStore.put(TLRPC.TL_decryptedMessageMediaVideo_old.constructor, TLRPC.TL_decryptedMessageMediaVideo_old.class); + classStore.put(TLRPC.TL_decryptedMessageMediaAudio_old.constructor, TLRPC.TL_decryptedMessageMediaAudio_old.class); + classStore.put(TLRPC.TL_audio_old.constructor, TLRPC.TL_audio_old.class); + classStore.put(TLRPC.TL_video_old.constructor, TLRPC.TL_video_old.class); } static TLClassStore store = null; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/TLObject.java b/TMessagesProj/src/main/java/org/telegram/messenger/TLObject.java index 9c40cb6e4..8ee8bc002 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/TLObject.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/TLObject.java @@ -42,4 +42,10 @@ public class TLObject { public void freeResources() { } + + public int getObjectSize() { + ByteBufferDesc bufferDesc = new ByteBufferDesc(true); + serializeToStream(bufferDesc); + return bufferDesc.length(); + } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/TLRPC.java b/TMessagesProj/src/main/java/org/telegram/messenger/TLRPC.java index 0cbc8368a..a2dad78c9 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/TLRPC.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/TLRPC.java @@ -140,6 +140,51 @@ public class TLRPC { } } + public static class NotifyPeer extends TLObject { + public Peer peer; + } + + public static class TL_notifyAll extends NotifyPeer { + public static int constructor = 0x74d07c60; + + + public void serializeToStream(AbsSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_notifyChats extends NotifyPeer { + public static int constructor = 0xc007cec3; + + + public void serializeToStream(AbsSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_notifyUsers extends NotifyPeer { + public static int constructor = 0xb4c83b4c; + + + public void serializeToStream(AbsSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_notifyPeer extends NotifyPeer { + public static int constructor = 0x9fd40bd8; + + + public void readParams(AbsSerializedData stream) { + peer = (Peer)TLClassStore.Instance().TLdeserialize(stream, stream.readInt32()); + } + + public void serializeToStream(AbsSerializedData stream) { + stream.writeInt32(constructor); + peer.serializeToStream(stream); + } + } + public static class TL_auth_checkedPhone extends TLObject { public static int constructor = 0xe300cc3b; @@ -1245,7 +1290,7 @@ public class TLRPC { } public static class TL_audio extends Audio { - public static int constructor = 0x427425e7; + public static int constructor = 0xc7ac6496; public void readParams(AbsSerializedData stream) { @@ -1254,6 +1299,7 @@ public class TLRPC { user_id = stream.readInt32(); date = stream.readInt32(); duration = stream.readInt32(); + mime_type = stream.readString(); size = stream.readInt32(); dc_id = stream.readInt32(); } @@ -1265,6 +1311,7 @@ public class TLRPC { stream.writeInt32(user_id); stream.writeInt32(date); stream.writeInt32(duration); + stream.writeString(mime_type); stream.writeInt32(size); stream.writeInt32(dc_id); } @@ -2515,7 +2562,7 @@ public class TLRPC { } public static class TL_video extends Video { - public static int constructor = 0x5a04a49f; + public static int constructor = 0x388fa391; public void readParams(AbsSerializedData stream) { @@ -2525,6 +2572,7 @@ public class TLRPC { date = stream.readInt32(); caption = stream.readString(); duration = stream.readInt32(); + mime_type = stream.readString(); size = stream.readInt32(); thumb = (PhotoSize)TLClassStore.Instance().TLdeserialize(stream, stream.readInt32()); dc_id = stream.readInt32(); @@ -2540,6 +2588,7 @@ public class TLRPC { stream.writeInt32(date); stream.writeString(caption); stream.writeInt32(duration); + stream.writeString(mime_type); stream.writeInt32(size); thumb.serializeToStream(stream); stream.writeInt32(dc_id); @@ -2820,7 +2869,7 @@ public class TLRPC { } public static class TL_inputMediaUploadedThumbVideo extends InputMedia { - public static int constructor = 0xe628a145; + public static int constructor = 0x9912dabf; public void readParams(AbsSerializedData stream) { @@ -2829,6 +2878,7 @@ public class TLRPC { duration = stream.readInt32(); w = stream.readInt32(); h = stream.readInt32(); + mime_type = stream.readString(); } public void serializeToStream(AbsSerializedData stream) { @@ -2838,6 +2888,7 @@ public class TLRPC { stream.writeInt32(duration); stream.writeInt32(w); stream.writeInt32(h); + stream.writeString(mime_type); } } @@ -2856,23 +2907,25 @@ public class TLRPC { } public static class TL_inputMediaUploadedAudio extends InputMedia { - public static int constructor = 0x61a6d436; + public static int constructor = 0x4e498cab; public void readParams(AbsSerializedData stream) { file = (InputFile)TLClassStore.Instance().TLdeserialize(stream, stream.readInt32()); duration = stream.readInt32(); + mime_type = stream.readString(); } public void serializeToStream(AbsSerializedData stream) { stream.writeInt32(constructor); file.serializeToStream(stream); stream.writeInt32(duration); + stream.writeString(mime_type); } } public static class TL_inputMediaUploadedVideo extends InputMedia { - public static int constructor = 0x4847d92a; + public static int constructor = 0x133ad6f6; public void readParams(AbsSerializedData stream) { @@ -2880,6 +2933,7 @@ public class TLRPC { duration = stream.readInt32(); w = stream.readInt32(); h = stream.readInt32(); + mime_type = stream.readString(); } public void serializeToStream(AbsSerializedData stream) { @@ -2888,6 +2942,7 @@ public class TLRPC { stream.writeInt32(duration); stream.writeInt32(w); stream.writeInt32(h); + stream.writeString(mime_type); } } @@ -3209,9 +3264,10 @@ public class TLRPC { } public static class TL_contacts_importedContacts extends TLObject { - public static int constructor = 0xd1cd0a4c; + public static int constructor = 0xad524315; public ArrayList imported = new ArrayList(); + public ArrayList retry_contacts = new ArrayList(); public ArrayList users = new ArrayList(); public void readParams(AbsSerializedData stream) { @@ -3222,6 +3278,11 @@ public class TLRPC { } stream.readInt32(); count = stream.readInt32(); + for (int a = 0; a < count; a++) { + retry_contacts.add(stream.readInt64()); + } + stream.readInt32(); + count = stream.readInt32(); for (int a = 0; a < count; a++) { users.add((User)TLClassStore.Instance().TLdeserialize(stream, stream.readInt32())); } @@ -3236,6 +3297,12 @@ public class TLRPC { imported.get(a).serializeToStream(stream); } stream.writeInt32(0x1cb5c415); + count = retry_contacts.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stream.writeInt64(retry_contacts.get(a)); + } + stream.writeInt32(0x1cb5c415); count = users.size(); stream.writeInt32(count); for (int a = 0; a < count; a++) { @@ -3275,6 +3342,8 @@ public class TLRPC { public ArrayList messages = new ArrayList(); public int pts; public int version; + public NotifyPeer peer; + public PeerNotifySettings notify_settings; public String first_name; public String last_name; public int qts; @@ -3283,6 +3352,7 @@ public class TLRPC { public ArrayList dc_options = new ArrayList(); public ChatParticipants participants; public EncryptedChat chat; + public boolean blocked; public long auth_key_id; public String device; public String location; @@ -3396,6 +3466,22 @@ public class TLRPC { } } + public static class TL_updateNotifySettings extends Update { + public static int constructor = 0xbec268ef; + + + public void readParams(AbsSerializedData stream) { + peer = (NotifyPeer)TLClassStore.Instance().TLdeserialize(stream, stream.readInt32()); + notify_settings = (PeerNotifySettings)TLClassStore.Instance().TLdeserialize(stream, stream.readInt32()); + } + + public void serializeToStream(AbsSerializedData stream) { + stream.writeInt32(constructor); + peer.serializeToStream(stream); + notify_settings.serializeToStream(stream); + } + } + public static class TL_updateUserTyping extends Update { public static int constructor = 0x6baa8508; @@ -3586,6 +3672,22 @@ public class TLRPC { } } + public static class TL_updateUserBlocked extends Update { + public static int constructor = 0x80ece81a; + + + public void readParams(AbsSerializedData stream) { + user_id = stream.readInt32(); + blocked = stream.readBool(); + } + + public void serializeToStream(AbsSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(user_id); + stream.writeBool(blocked); + } + } + public static class TL_updateActivation extends Update { public static int constructor = 0x6f690963; @@ -3847,6 +3949,7 @@ public class TLRPC { } public static class DecryptedMessageAction extends TLObject { + public int layer; public int ttl_seconds; public ArrayList random_ids = new ArrayList(); } @@ -3872,6 +3975,43 @@ public class TLRPC { } } + public static class TL_decryptedMessageActionNotifyLayer extends DecryptedMessageAction { + public static int constructor = 0xf3048883; + + + public void readParams(AbsSerializedData stream) { + layer = stream.readInt32(); + } + + public void serializeToStream(AbsSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(layer); + } + } + + public static class TL_decryptedMessageActionReadMessages extends DecryptedMessageAction { + public static int constructor = 0xc4f40be; + + + public void readParams(AbsSerializedData stream) { + stream.readInt32(); + int count = stream.readInt32(); + for (int a = 0; a < count; a++) { + random_ids.add(stream.readInt64()); + } + } + + public void serializeToStream(AbsSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(0x1cb5c415); + int count = random_ids.size(); + stream.writeInt32(count); + for (Long random_id : random_ids) { + stream.writeInt64(random_id); + } + } + } + public static class contacts_MyLink extends TLObject { public boolean contact; } @@ -4497,11 +4637,12 @@ public class TLRPC { } public static class TL_decryptedMessageMediaAudio extends DecryptedMessageMedia { - public static int constructor = 0x6080758f; + public static int constructor = 0x57e0a9cb; public void readParams(AbsSerializedData stream) { duration = stream.readInt32(); + mime_type = stream.readString(); size = stream.readInt32(); key = stream.readByteArray(); iv = stream.readByteArray(); @@ -4510,6 +4651,7 @@ public class TLRPC { public void serializeToStream(AbsSerializedData stream) { stream.writeInt32(constructor); stream.writeInt32(duration); + stream.writeString(mime_type); stream.writeInt32(size); stream.writeByteArray(key); stream.writeByteArray(iv); @@ -4517,7 +4659,7 @@ public class TLRPC { } public static class TL_decryptedMessageMediaVideo extends DecryptedMessageMedia { - public static int constructor = 0x4cee6ef3; + public static int constructor = 0x524a415d; public void readParams(AbsSerializedData stream) { @@ -4525,6 +4667,7 @@ public class TLRPC { thumb_w = stream.readInt32(); thumb_h = stream.readInt32(); duration = stream.readInt32(); + mime_type = stream.readString(); w = stream.readInt32(); h = stream.readInt32(); size = stream.readInt32(); @@ -4538,6 +4681,7 @@ public class TLRPC { stream.writeInt32(thumb_w); stream.writeInt32(thumb_h); stream.writeInt32(duration); + stream.writeString(mime_type); stream.writeInt32(w); stream.writeInt32(h); stream.writeInt32(size); @@ -6169,31 +6313,6 @@ public class TLRPC { } } - public static class TL_set_client_DH_params extends TLObject { - public static int constructor = 0xf5045f1f; - - public byte[] nonce; - public byte[] server_nonce; - public byte[] encrypted_data; - - public Class responseClass () { - return Set_client_DH_params_answer.class; - } - - public void readParams(AbsSerializedData stream) { - nonce = stream.readData(16); - server_nonce = stream.readData(16); - encrypted_data = stream.readByteArray(); - } - - public void serializeToStream(AbsSerializedData stream) { - stream.writeInt32(constructor); - stream.writeRaw(nonce); - stream.writeRaw(server_nonce); - stream.writeByteArray(encrypted_data); - } - } - public static class TL_auth_checkPhone extends TLObject { public static int constructor = 0x6fe51dfb; @@ -8000,59 +8119,6 @@ public class TLRPC { } } - public static class TL_messages_sendEncrypted extends TLObject { - public static int constructor = 0xa9776773; - - public TL_inputEncryptedChat peer; - public long random_id; - public byte[] data; - - public Class responseClass () { - return messages_SentEncryptedMessage.class; - } - - public void readParams(AbsSerializedData stream) { - peer = (TL_inputEncryptedChat)TLClassStore.Instance().TLdeserialize(stream, stream.readInt32()); - random_id = stream.readInt64(); - data = stream.readByteArray(); - } - - public void serializeToStream(AbsSerializedData stream) { - stream.writeInt32(constructor); - peer.serializeToStream(stream); - stream.writeInt64(random_id); - stream.writeByteArray(data); - } - } - - public static class TL_messages_sendEncryptedFile extends TLObject { - public static int constructor = 0x9a901b66; - - public TL_inputEncryptedChat peer; - public long random_id; - public byte[] data; - public InputEncryptedFile file; - - public Class responseClass () { - return messages_SentEncryptedMessage.class; - } - - public void readParams(AbsSerializedData stream) { - peer = (TL_inputEncryptedChat)TLClassStore.Instance().TLdeserialize(stream, stream.readInt32()); - random_id = stream.readInt64(); - data = stream.readByteArray(); - file = (InputEncryptedFile)TLClassStore.Instance().TLdeserialize(stream, stream.readInt32()); - } - - public void serializeToStream(AbsSerializedData stream) { - stream.writeInt32(constructor); - peer.serializeToStream(stream); - stream.writeInt64(random_id); - stream.writeByteArray(data); - file.serializeToStream(stream); - } - } - public static class TL_messages_sendEncryptedService extends TLObject { public static int constructor = 0x32d439a4; @@ -8080,6 +8146,98 @@ public class TLRPC { //manually created + public static class TL_set_client_DH_params extends TLObject { + public static int constructor = 0xf5045f1f; + + public byte[] nonce; + public byte[] server_nonce; + public ByteBufferDesc encrypted_data; + + public Class responseClass () { + return Set_client_DH_params_answer.class; + } + + public void serializeToStream(AbsSerializedData stream) { + stream.writeInt32(constructor); + stream.writeRaw(nonce); + stream.writeRaw(server_nonce); + stream.writeByteBuffer(encrypted_data); + } + + @Override + public void freeResources() { + if (disableFree) { + return; + } + if (encrypted_data != null) { + BuffersStorage.getInstance().reuseFreeBuffer(encrypted_data); + encrypted_data = null; + } + } + } + + public static class TL_messages_sendEncrypted extends TLObject { + public static int constructor = 0xa9776773; + + public TL_inputEncryptedChat peer; + public long random_id; + public ByteBufferDesc data; + + public Class responseClass () { + return messages_SentEncryptedMessage.class; + } + + public void serializeToStream(AbsSerializedData stream) { + stream.writeInt32(constructor); + peer.serializeToStream(stream); + stream.writeInt64(random_id); + stream.writeByteBuffer(data); + } + + @Override + public void freeResources() { + if (disableFree) { + return; + } + if (data != null) { + BuffersStorage.getInstance().reuseFreeBuffer(data); + data = null; + } + } + } + + public static class TL_messages_sendEncryptedFile extends TLObject { + public static int constructor = 0x9a901b66; + + public TL_inputEncryptedChat peer; + public long random_id; + public ByteBufferDesc data; + public InputEncryptedFile file; + + public Class responseClass () { + return messages_SentEncryptedMessage.class; + } + + public void serializeToStream(AbsSerializedData stream) { + stream.writeInt32(constructor); + peer.serializeToStream(stream); + stream.writeInt64(random_id); + stream.writeByteBuffer(data); + file.serializeToStream(stream); + } + + @Override + public void freeResources() { + if (disableFree) { + return; + } + if (data != null) { + BuffersStorage.getInstance().reuseFreeBuffer(data); + data = null; + } + } + } + public static class UserStatus extends TLObject { public int expires; } @@ -8313,6 +8471,7 @@ public class TLRPC { for (int a = 0; a < count; a++) { TL_futureSalt salt = new TL_futureSalt(); salt.readParams(stream); + salts.add(salt); } } @@ -8692,11 +8851,12 @@ public class TLRPC { } public static class TL_dialog extends TLObject { - public static int constructor = 0x214a8cdf; + public static int constructor = 0xab3a99ac; public Peer peer; public int top_message; public int unread_count; + public PeerNotifySettings notify_settings; public int last_message_date; public long id; public int last_read; @@ -8705,6 +8865,7 @@ public class TLRPC { peer = (Peer)TLClassStore.Instance().TLdeserialize(stream, stream.readInt32()); top_message = stream.readInt32(); unread_count = stream.readInt32(); + notify_settings = (PeerNotifySettings)TLClassStore.Instance().TLdeserialize(stream, stream.readInt32()); } public void serializeToStream(AbsSerializedData stream) { @@ -8712,6 +8873,7 @@ public class TLRPC { peer.serializeToStream(stream); stream.writeInt32(top_message); stream.writeInt32(unread_count); + notify_settings.serializeToStream(stream); } } @@ -8770,6 +8932,7 @@ public class TLRPC { public int date; public String caption; public int duration; + public String mime_type; public int size; public PhotoSize thumb; public int dc_id; @@ -8801,6 +8964,7 @@ public class TLRPC { public int user_id; public int date; public int duration; + public String mime_type; public int size; public int dc_id; public String path; @@ -8974,8 +9138,8 @@ public class TLRPC { } } - public static class invokeWithLayer12 extends TLObject { - public static int constructor = 0xdda60d3c; + public static class invokeWithLayer14 extends TLObject { + public static int constructor = 0x2b9b08fa; public TLObject query; @@ -9226,4 +9390,114 @@ public class TLRPC { public byte[] key; public byte[] iv; } + + public static class TL_decryptedMessageMediaVideo_old extends TL_decryptedMessageMediaVideo { + public static int constructor = 0x4cee6ef3; + + + public void readParams(AbsSerializedData stream) { + thumb = stream.readByteArray(); + thumb_w = stream.readInt32(); + thumb_h = stream.readInt32(); + duration = stream.readInt32(); + w = stream.readInt32(); + h = stream.readInt32(); + size = stream.readInt32(); + key = stream.readByteArray(); + iv = stream.readByteArray(); + } + + public void serializeToStream(AbsSerializedData stream) { + stream.writeInt32(constructor); + stream.writeByteArray(thumb); + stream.writeInt32(thumb_w); + stream.writeInt32(thumb_h); + stream.writeInt32(duration); + stream.writeInt32(w); + stream.writeInt32(h); + stream.writeInt32(size); + stream.writeByteArray(key); + stream.writeByteArray(iv); + } + } + + public static class TL_decryptedMessageMediaAudio_old extends TL_decryptedMessageMediaAudio { + public static int constructor = 0x6080758f; + + + public void readParams(AbsSerializedData stream) { + duration = stream.readInt32(); + size = stream.readInt32(); + key = stream.readByteArray(); + iv = stream.readByteArray(); + } + + public void serializeToStream(AbsSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(duration); + stream.writeInt32(size); + stream.writeByteArray(key); + stream.writeByteArray(iv); + } + } + + public static class TL_audio_old extends TL_audio { + public static int constructor = 0x427425e7; + + + public void readParams(AbsSerializedData 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(); + } + + public void serializeToStream(AbsSerializedData 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); + } + } + + public static class TL_video_old extends TL_video { + public static int constructor = 0x5a04a49f; + + + public void readParams(AbsSerializedData stream) { + id = stream.readInt64(); + access_hash = stream.readInt64(); + user_id = stream.readInt32(); + date = stream.readInt32(); + caption = stream.readString(); + duration = stream.readInt32(); + size = stream.readInt32(); + thumb = (PhotoSize)TLClassStore.Instance().TLdeserialize(stream, stream.readInt32()); + dc_id = stream.readInt32(); + w = stream.readInt32(); + h = stream.readInt32(); + } + + public void serializeToStream(AbsSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(id); + stream.writeInt64(access_hash); + stream.writeInt32(user_id); + stream.writeInt32(date); + stream.writeString(caption); + stream.writeInt32(duration); + stream.writeInt32(size); + thumb.serializeToStream(stream); + stream.writeInt32(dc_id); + stream.writeInt32(w); + stream.writeInt32(h); + } + } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/TcpConnection.java b/TMessagesProj/src/main/java/org/telegram/messenger/TcpConnection.java index 717cb3297..263ed8fdc 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/TcpConnection.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/TcpConnection.java @@ -33,7 +33,6 @@ public class TcpConnection extends ConnectionContext { public abstract void tcpConnectionConnected(TcpConnection connection); public abstract void tcpConnectionQuiackAckReceived(TcpConnection connection, int ack); public abstract void tcpConnectionReceivedData(TcpConnection connection, ByteBufferDesc data, int length); - public abstract void tcpConnectionProgressChanged(TcpConnection connection, long messageId, int currentSize, int length); } private static PyroSelector selector; @@ -46,7 +45,6 @@ public class TcpConnection extends ConnectionContext { private int failedConnectionCount; public TcpConnectionDelegate delegate; private ByteBufferDesc restOfTheData; - private long lastMessageId = 0; private boolean hasSomeDataSinceLastConnect = false; private int willRetryConnectCount = 5; private boolean isNextPort = false; @@ -284,8 +282,8 @@ public class TcpConnection extends ConnectionContext { connect(); } - public void sendData(final byte[] data, final ByteBufferDesc buff, final boolean reportAck) { - if (data == null && buff == null) { + public void sendData(final ByteBufferDesc buff, final boolean canReuse, final boolean reportAck) { + if (buff == null) { return; } selector.scheduleTask(new Runnable() { @@ -298,16 +296,13 @@ public class TcpConnection extends ConnectionContext { } if (client == null || client.isDisconnected()) { - BuffersStorage.getInstance().reuseFreeBuffer(buff); + if (canReuse) { + BuffersStorage.getInstance().reuseFreeBuffer(buff); + } return; } - int bufferLen = 0; - if (data != null) { - bufferLen = data.length; - } else if (buff != null) { - bufferLen = buff.limit(); - } + int bufferLen = buff.limit(); int packetLength = bufferLen / 4; if (packetLength < 0x7f) { @@ -336,10 +331,9 @@ public class TcpConnection extends ConnectionContext { } buffer.writeInt32(packetLength); } - if (data != null) { - buffer.writeRaw(data); - } else { - buffer.writeRaw(buff); + + buffer.writeRaw(buff); + if (canReuse) { BuffersStorage.getInstance().reuseFreeBuffer(buff); } @@ -389,19 +383,6 @@ public class TcpConnection extends ConnectionContext { buffer.limit(oldLimit); if (restOfTheData.position() != lastPacketLength) { //FileLog.e("tmessages", this + " don't get much data to restOfTheData"); - if (lastMessageId != -1 && lastMessageId != 0) { - if (delegate != null) { - final TcpConnectionDelegate finalDelegate = delegate; - final int arg2 = restOfTheData.position(); - final int arg3 = lastPacketLength; - Utilities.stageQueue.postRunnable(new Runnable() { - @Override - public void run() { - finalDelegate.tcpConnectionProgressChanged(TcpConnection.this, lastMessageId, arg2, arg3); - } - }); - } - } return; } else { //FileLog.e("tmessages", this + " get much data to restOfTheData - OK!"); @@ -424,7 +405,7 @@ public class TcpConnection extends ConnectionContext { datacenter.storeCurrentAddressAndPortNum(); isNextPort = false; if ((transportRequestClass & RPCRequest.RPCRequestClassPush) != 0) { - client.setTimeout(60000 * 3 + 20000); + client.setTimeout(60000 * 15); } else { client.setTimeout(25000); } @@ -497,32 +478,10 @@ public class TcpConnection extends ConnectionContext { if (currentPacketLength < buffer.remaining()) { FileLog.d("tmessages", TcpConnection.this + " Received message len " + currentPacketLength + " but packet larger " + buffer.remaining()); - lastMessageId = 0; } else if (currentPacketLength == buffer.remaining()) { FileLog.d("tmessages", TcpConnection.this + " Received message len " + currentPacketLength + " equal to packet size"); - lastMessageId = 0; } else { FileLog.d("tmessages", TcpConnection.this + " Received packet size less(" + buffer.remaining() + ") then message size(" + currentPacketLength + ")"); - if (buffer.remaining() >= 152 && (transportRequestClass & RPCRequest.RPCRequestClassDownloadMedia) != 0) { - if (lastMessageId == 0) { - byte[] temp = new byte[152]; - buffer.get(temp); - lastMessageId = ConnectionsManager.getInstance().needsToDecodeMessageIdFromPartialData(TcpConnection.this, temp); - } - if (lastMessageId != -1 && lastMessageId != 0) { - if (delegate != null) { - final TcpConnectionDelegate finalDelegate = delegate; - final int arg2 = buffer.remaining(); - final int arg3 = currentPacketLength; - Utilities.stageQueue.postRunnable(new Runnable() { - @Override - public void run() { - finalDelegate.tcpConnectionProgressChanged(TcpConnection.this, lastMessageId, arg2, arg3); - } - }); - } - } - } ByteBufferDesc reuseLater = null; int len = currentPacketLength + (fByte != 0x7f ? 1 : 4); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/UserConfig.java b/TMessagesProj/src/main/java/org/telegram/messenger/UserConfig.java index 4869a96f0..34b469785 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/UserConfig.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/UserConfig.java @@ -12,6 +12,7 @@ import android.content.Context; import android.content.SharedPreferences; import android.util.Base64; +import org.telegram.android.MessagesStorage; import org.telegram.ui.ApplicationLoader; import java.io.File; @@ -197,6 +198,5 @@ public class UserConfig { contactsVersion = 1; saveIncomingPhotos = false; saveConfig(true); - MessagesController.getInstance().deleteAllAppAccounts(); } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/Utilities.java b/TMessagesProj/src/main/java/org/telegram/messenger/Utilities.java index 59b64ffcc..906654005 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/Utilities.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/Utilities.java @@ -14,11 +14,8 @@ import android.content.ContentUris; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; -import android.content.pm.ActivityInfo; import android.content.res.Configuration; import android.database.Cursor; -import android.graphics.Point; -import android.graphics.Typeface; import android.net.Uri; import android.os.Build; import android.os.Environment; @@ -27,16 +24,12 @@ import android.provider.MediaStore; import android.text.Html; import android.text.SpannableStringBuilder; import android.util.Base64; -import android.view.Display; -import android.view.Surface; -import android.view.View; -import android.view.WindowManager; -import android.view.inputmethod.InputMethodManager; import net.hockeyapp.android.CrashManager; import net.hockeyapp.android.CrashManagerListener; import net.hockeyapp.android.UpdateManager; +import org.telegram.android.LocaleController; import org.telegram.ui.ApplicationLoader; import java.io.ByteArrayInputStream; @@ -49,7 +42,6 @@ import java.io.InputStream; import java.io.OutputStream; import java.math.BigInteger; import java.nio.ByteBuffer; -import java.nio.ByteOrder; import java.nio.channels.FileChannel; import java.security.KeyFactory; import java.security.MessageDigest; @@ -59,7 +51,6 @@ import java.security.spec.RSAPublicKeySpec; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; -import java.util.Hashtable; import java.util.Locale; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -69,16 +60,9 @@ import java.util.zip.GZIPOutputStream; import javax.crypto.Cipher; public class Utilities { - public static int statusBarHeight = 0; - public static float density = 1; - public static Point displaySize = new Point(); public static Pattern pattern = Pattern.compile("[0-9]+"); public static SecureRandom random = new SecureRandom(); private final static Integer lock = 1; - private static int prevOrientation = -10; - - private static boolean waitingForSms = false; - private static final Integer smsLock = 2; public static ArrayList goodPrimes = new ArrayList(); @@ -108,12 +92,8 @@ public class Utilities { R.drawable.group_blue, R.drawable.group_yellow}; - public static int externalCacheNotAvailableState = 0; - final protected static char[] hexArray = "0123456789ABCDEF".toCharArray(); - private static final Hashtable cache = new Hashtable(); - public static ProgressDialog progressDialog; static { @@ -128,7 +108,6 @@ public class Utilities { FileLog.e("tmessages", e); } - density = ApplicationLoader.applicationContext.getResources().getDisplayMetrics().density; SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("primes", Context.MODE_PRIVATE); String primes = preferences.getString("primes", null); if (primes == null) { @@ -149,96 +128,14 @@ public class Utilities { goodPrimes.add("C71CAEB9C6B1C9048E6C522F70F13F73980D40238E3E21C14934D037563D930F48198A0AA7C14058229493D22530F4DBFA336F6E0AC925139543AED44CCE7C3720FD51F69458705AC68CD4FE6B6B13ABDC9746512969328454F18FAF8C595F642477FE96BB2A941D5BCD1D4AC8CC49880708FA9B378E3C4F3A9060BEE67CF9A4A4A695811051907E162753B56B0F6B410DBA74D8A84B2A14B3144E0EF1284754FD17ED950D5965B4B9DD46582DB1178D169C6BC465B0D6FF9CA3928FEF5B9AE4E418FC15E83EBEA0F87FA9FF5EED70050DED2849F47BF959D956850CE929851F0D8115F635B105EE2E4E15D04B2454BF6F4FADF034B10403119CD8E3B92FCC5B"); } } - - checkDisplaySize(); } public native static long doPQNative(long _what); - public native static byte[] aesIgeEncryption(byte[] _what, byte[] _key, byte[] _iv, boolean encrypt, boolean changeIv, int len); - public native static void aesIgeEncryption2(ByteBuffer _what, byte[] _key, byte[] _iv, boolean encrypt, boolean changeIv, int len); public native static void loadBitmap(String path, int[] bitmap, int scale, int format, int width, int height); + private native static void aesIgeEncryption(ByteBuffer buffer, byte[] key, byte[] iv, boolean encrypt, int offset, int length); - public static void lockOrientation(Activity activity) { - if (prevOrientation != -10) { - return; - } - try { - prevOrientation = activity.getRequestedOrientation(); - WindowManager manager = (WindowManager)activity.getSystemService(Activity.WINDOW_SERVICE); - if (manager != null && manager.getDefaultDisplay() != null) { - int rotation = manager.getDefaultDisplay().getRotation(); - int orientation = activity.getResources().getConfiguration().orientation; - - if (rotation == Surface.ROTATION_270) { - if (orientation == Configuration.ORIENTATION_PORTRAIT) { - activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); - } else { - if (Build.VERSION.SDK_INT >= 9) { - activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE); - } else { - activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); - } - } - } else if (rotation == Surface.ROTATION_90) { - if (orientation == Configuration.ORIENTATION_PORTRAIT) { - if (Build.VERSION.SDK_INT >= 9) { - activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT); - } else { - activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); - } - } else { - activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); - } - } else if (rotation == Surface.ROTATION_0) { - if (orientation == Configuration.ORIENTATION_LANDSCAPE) { - activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); - } else { - activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); - } - } else { - if (orientation == Configuration.ORIENTATION_LANDSCAPE) { - if (Build.VERSION.SDK_INT >= 9) { - activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE); - } else { - activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); - } - } else { - if (Build.VERSION.SDK_INT >= 9) { - activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT); - } else { - activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); - } - } - } - } - } catch (Exception e) { - FileLog.e("tmessages", e); - } - } - - public static void unlockOrientation(Activity activity) { - try { - if (prevOrientation != -10) { - activity.setRequestedOrientation(prevOrientation); - prevOrientation = -10; - } - } catch (Exception e) { - FileLog.e("tmessages", e); - } - } - - public static boolean isWaitingForSms() { - boolean value = false; - synchronized (smsLock) { - value = waitingForSms; - } - return value; - } - - public static void setWaitingForSms(boolean value) { - synchronized (smsLock) { - waitingForSms = value; - } + public static void aesIgeEncryption(ByteBuffer buffer, byte[] key, byte[] iv, boolean encrypt, boolean changeIv, int offset, int length) { + aesIgeEncryption(buffer, key, changeIv ? iv : iv.clone(), encrypt, offset, length); } public static Integer parseInt(String value) { @@ -259,22 +156,6 @@ public class Utilities { return null; } - public static File getCacheDir() { - if (externalCacheNotAvailableState == 1 || externalCacheNotAvailableState == 0 && Environment.getExternalStorageState().startsWith(Environment.MEDIA_MOUNTED)) { - externalCacheNotAvailableState = 1; - File file = ApplicationLoader.applicationContext.getExternalCacheDir(); - if (file != null) { - return file; - } - } - externalCacheNotAvailableState = 2; - File file = ApplicationLoader.applicationContext.getCacheDir(); - if (file != null) { - return file; - } - return new File(""); - } - public static String bytesToHex(byte[] bytes) { char[] hexChars = new char[bytes.length * 2]; int v; @@ -286,14 +167,6 @@ public class Utilities { return new String(hexChars); } - public static int dp(int value) { - return (int)(Math.max(1, density * value)); - } - - public static int dpf(float value) { - return (int)Math.ceil(density * value); - } - public static boolean isGoodPrime(byte[] prime, int g) { if (!(g >= 2 && g <= 7)) { return false; @@ -401,6 +274,18 @@ public class Utilities { } } + public static boolean arraysEquals(byte[] arr1, int offset1, byte[] arr2, int offset2) { + if (arr1 == null || arr2 == null || arr1.length - offset1 != arr2.length - offset2 || arr1.length - offset1 < 0) { + return false; + } + for (int a = offset1; a < arr1.length; a++) { + if (arr1[a + offset1] != arr2[a + offset2]) { + return false; + } + } + return true; + } + public static byte[] computeSHA1(byte[] convertme, int offset, int len) { try { MessageDigest md = MessageDigest.getInstance("SHA-1"); @@ -413,30 +298,29 @@ public class Utilities { } public static byte[] computeSHA1(ByteBuffer convertme, int offset, int len) { + int oldp = convertme.position(); + int oldl = convertme.limit(); try { MessageDigest md = MessageDigest.getInstance("SHA-1"); - int oldp = convertme.position(); - int oldl = convertme.limit(); convertme.position(offset); convertme.limit(len); md.update(convertme); - convertme.position(oldp); - convertme.limit(oldl); return md.digest(); } catch (Exception e) { FileLog.e("tmessages", e); + } finally { + convertme.limit(oldl); + convertme.position(oldp); } return null; } + public static byte[] computeSHA1(ByteBuffer convertme) { + return computeSHA1(convertme, 0, convertme.limit()); + } + public static byte[] computeSHA1(byte[] convertme) { - try { - MessageDigest md = MessageDigest.getInstance("SHA-1"); - return md.digest(convertme); - } catch (Exception e) { - FileLog.e("tmessages", e); - } - return null; + return computeSHA1(convertme, 0, convertme.length); } public static byte[] encryptWithRSA(BigInteger[] key, byte[] data) { @@ -453,26 +337,9 @@ public class Utilities { return null; } - public static byte[] longToBytes(long x) { - ByteBuffer buffer = ByteBuffer.allocate(8); - buffer.putLong(x); - return buffer.array(); - } - public static long bytesToLong(byte[] bytes) { - ByteBuffer buffer = ByteBuffer.allocate(8); - buffer.order(ByteOrder.LITTLE_ENDIAN); - buffer.put(bytes); - buffer.flip(); - return buffer.getLong(); - } - - public static int bytesToInt(byte[] bytes) { - ByteBuffer buffer = ByteBuffer.allocate(4); - buffer.order(ByteOrder.LITTLE_ENDIAN); - buffer.put(bytes); - buffer.flip(); - return buffer.getInt(); + return ((long) bytes[7] << 56) + (((long) bytes[6] & 0xFF) << 48) + (((long) bytes[5] & 0xFF) << 40) + (((long) bytes[4] & 0xFF) << 32) + + (((long) bytes[3] & 0xFF) << 24) + (((long) bytes[2] & 0xFF) << 16) + (((long) bytes[1] & 0xFF) << 8) + ((long) bytes[0] & 0xFF); } public static MessageKeyData generateMessageKeyData(byte[] authKey, byte[] messageKey, boolean incoming) { @@ -562,51 +429,6 @@ public class Utilities { return packedData; } - public static Typeface getTypeface(String assetPath) { - synchronized (cache) { - if (!cache.containsKey(assetPath)) { - try { - Typeface t = Typeface.createFromAsset(ApplicationLoader.applicationContext.getAssets(), - assetPath); - cache.put(assetPath, t); - } catch (Exception e) { - FileLog.e("Typefaces", "Could not get typeface '" + assetPath + "' because " + e.getMessage()); - return null; - } - } - return cache.get(assetPath); - } - } - - public static void showKeyboard(View view) { - if (view == null) { - return; - } - InputMethodManager inputManager = (InputMethodManager)view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); - inputManager.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT); - - ((InputMethodManager) view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE)).showSoftInput(view, 0); - } - - public static boolean isKeyboardShowed(View view) { - if (view == null) { - return false; - } - InputMethodManager inputManager = (InputMethodManager) view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); - return inputManager.isActive(view); - } - - public static void hideKeyboard(View view) { - if (view == null) { - return; - } - InputMethodManager imm = (InputMethodManager) view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); - if (!imm.isActive()) { - return; - } - imm.hideSoftInputFromWindow(view.getWindowToken(), 0); - } - public static void ShowProgressDialog(final Activity activity, final String message) { activity.runOnUiThread(new Runnable() { @Override @@ -624,25 +446,6 @@ public class Utilities { }); } - public static void checkDisplaySize() { - try { - WindowManager manager = (WindowManager)ApplicationLoader.applicationContext.getSystemService(Context.WINDOW_SERVICE); - if (manager != null) { - Display display = manager.getDefaultDisplay(); - if (display != null) { - if(android.os.Build.VERSION.SDK_INT < 13) { - displaySize.set(display.getWidth(), display.getHeight()); - } else { - display.getSize(displaySize); - } - FileLog.e("tmessages", "display size = " + displaySize.x + " " + displaySize.y); - } - } - } catch (Exception e) { - FileLog.e("tmessages", e); - } - } - public static void HideProgressDialog(Activity activity) { activity.runOnUiThread(new Runnable() { @Override diff --git a/TMessagesProj/src/main/java/org/telegram/objects/MessageObject.java b/TMessagesProj/src/main/java/org/telegram/objects/MessageObject.java index c3a28d8aa..168ec0a8e 100644 --- a/TMessagesProj/src/main/java/org/telegram/objects/MessageObject.java +++ b/TMessagesProj/src/main/java/org/telegram/objects/MessageObject.java @@ -16,12 +16,13 @@ import android.text.StaticLayout; import android.text.TextPaint; import android.text.util.Linkify; +import org.telegram.android.AndroidUtilities; import org.telegram.messenger.FileLog; -import org.telegram.messenger.LocaleController; +import org.telegram.android.LocaleController; import org.telegram.messenger.TLObject; import org.telegram.messenger.TLRPC; -import org.telegram.messenger.Emoji; -import org.telegram.messenger.MessagesController; +import org.telegram.android.Emoji; +import org.telegram.android.MessagesController; import org.telegram.messenger.R; import org.telegram.messenger.UserConfig; import org.telegram.messenger.Utilities; @@ -68,7 +69,7 @@ public class MessageObject { textPaint.linkColor = 0xff316f9f; } - textPaint.setTextSize(Utilities.dp(MessagesController.getInstance().fontSize)); + textPaint.setTextSize(AndroidUtilities.dp(MessagesController.getInstance().fontSize)); messageOwner = message; @@ -271,7 +272,7 @@ public class MessageObject { } else { messageText = message.message; } - messageText = Emoji.replaceEmoji(messageText, textPaint.getFontMetricsInt(), Utilities.dp(20)); + messageText = Emoji.replaceEmoji(messageText, textPaint.getFontMetricsInt(), AndroidUtilities.dp(20)); if (message instanceof TLRPC.TL_message || (message instanceof TLRPC.TL_messageForwarded && (message.media == null || !(message.media instanceof TLRPC.TL_messageMediaEmpty)))) { if (message.media == null || message.media instanceof TLRPC.TL_messageMediaEmpty) { @@ -397,9 +398,9 @@ public class MessageObject { int maxWidth; if (messageOwner.to_id.chat_id != 0) { - maxWidth = Math.min(Utilities.displaySize.x, Utilities.displaySize.y) - Utilities.dp(122); + maxWidth = Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) - AndroidUtilities.dp(122); } else { - maxWidth = Math.min(Utilities.displaySize.x, Utilities.displaySize.y) - Utilities.dp(80); + maxWidth = Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) - AndroidUtilities.dp(80); } StaticLayout textLayout = null; @@ -539,4 +540,18 @@ public class MessageObject { public boolean isFromMe() { return messageOwner.from_id == UserConfig.getClientUserId(); } + + public long getDialogId() { + if (messageOwner.dialog_id != 0) { + return messageOwner.dialog_id; + } else { + if (messageOwner.to_id.chat_id != 0) { + return -messageOwner.to_id.chat_id; + } else if (isFromMe()) { + return messageOwner.to_id.user_id; + } else { + return messageOwner.from_id; + } + } + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/ContactsActivityAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/ContactsActivityAdapter.java index f341e93af..190f99985 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/ContactsActivityAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/ContactsActivityAdapter.java @@ -14,10 +14,10 @@ import android.view.View; import android.view.ViewGroup; import android.widget.TextView; -import org.telegram.messenger.LocaleController; +import org.telegram.android.LocaleController; import org.telegram.messenger.TLRPC; -import org.telegram.messenger.ContactsController; -import org.telegram.messenger.MessagesController; +import org.telegram.android.ContactsController; +import org.telegram.android.MessagesController; import org.telegram.messenger.R; import org.telegram.ui.Cells.ChatOrUserCell; import org.telegram.ui.Views.SectionedBaseAdapter; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/ContactsActivitySearchAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/ContactsActivitySearchAdapter.java index 0da5808d1..b7436d735 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/ContactsActivitySearchAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/ContactsActivitySearchAdapter.java @@ -13,9 +13,9 @@ import android.view.View; import android.view.ViewGroup; import org.telegram.messenger.TLRPC; -import org.telegram.messenger.ContactsController; +import org.telegram.android.ContactsController; import org.telegram.messenger.FileLog; -import org.telegram.messenger.MessagesController; +import org.telegram.android.MessagesController; import org.telegram.messenger.UserConfig; import org.telegram.messenger.Utilities; import org.telegram.ui.Cells.ChatOrUserCell; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ApplicationLoader.java b/TMessagesProj/src/main/java/org/telegram/ui/ApplicationLoader.java index 52a7660ea..f93145ef6 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ApplicationLoader.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ApplicationLoader.java @@ -29,14 +29,15 @@ import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.GooglePlayServicesUtil; import com.google.android.gms.gcm.GoogleCloudMessaging; -import org.telegram.messenger.NotificationsService; +import org.telegram.android.AndroidUtilities; +import org.telegram.android.NotificationsService; import org.telegram.messenger.BuildVars; import org.telegram.messenger.ConnectionsManager; import org.telegram.messenger.FileLog; -import org.telegram.messenger.LocaleController; -import org.telegram.messenger.MessagesController; -import org.telegram.messenger.NativeLoader; -import org.telegram.messenger.ScreenReceiver; +import org.telegram.android.LocaleController; +import org.telegram.android.MessagesController; +import org.telegram.android.NativeLoader; +import org.telegram.android.ScreenReceiver; import org.telegram.messenger.UserConfig; import org.telegram.messenger.Utilities; @@ -57,6 +58,7 @@ public class ApplicationLoader extends Application { private static volatile boolean applicationInited = false; public static volatile boolean isScreenOn = false; + public static volatile boolean mainInterfacePaused = true; public static void postInitApplication() { if (applicationInited) { @@ -65,8 +67,6 @@ public class ApplicationLoader extends Application { applicationInited = true; - NativeLoader.initNativeLibs(applicationContext); - try { LocaleController.getInstance(); } catch (Exception e) { @@ -134,6 +134,7 @@ public class ApplicationLoader extends Application { public void onCreate() { super.onCreate(); applicationContext = getApplicationContext(); + NativeLoader.initNativeLibs(ApplicationLoader.applicationContext); applicationHandler = new Handler(applicationContext.getMainLooper()); @@ -177,7 +178,7 @@ public class ApplicationLoader extends Application { super.onConfigurationChanged(newConfig); try { LocaleController.getInstance().onDeviceConfigurationChange(newConfig); - Utilities.checkDisplaySize(); + AndroidUtilities.checkDisplaySize(); } catch (Exception e) { e.printStackTrace(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatAudioCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatAudioCell.java index 10d5c1cda..0c61b173b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatAudioCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatAudioCell.java @@ -16,12 +16,12 @@ import android.text.StaticLayout; import android.text.TextPaint; import android.view.MotionEvent; import android.view.SoundEffectConstants; -import android.view.View; +import org.telegram.android.AndroidUtilities; import org.telegram.messenger.FileLoader; -import org.telegram.messenger.MediaController; +import org.telegram.android.MediaController; import org.telegram.messenger.TLRPC; -import org.telegram.messenger.MessagesController; +import org.telegram.android.MessagesController; import org.telegram.messenger.R; import org.telegram.messenger.Utilities; import org.telegram.objects.MessageObject; @@ -30,7 +30,6 @@ import org.telegram.ui.Views.ProgressView; import org.telegram.ui.Views.SeekBar; import java.io.File; -import java.lang.ref.WeakReference; public class ChatAudioCell extends ChatBaseCell implements SeekBar.SeekBarDelegate, MediaController.FileDownloadProgressListener { @@ -90,7 +89,7 @@ public class ChatAudioCell extends ChatBaseCell implements SeekBar.SeekBarDelega statesDrawable[7][1] = getResources().getDrawable(R.drawable.audiocancel2_pressed); timePaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); - timePaint.setTextSize(Utilities.dp(12)); + timePaint.setTextSize(AndroidUtilities.dp(12)); } } @@ -115,7 +114,7 @@ public class ChatAudioCell extends ChatBaseCell implements SeekBar.SeekBarDelega } invalidate(); } else { - int side = Utilities.dp(36); + int side = AndroidUtilities.dp(36); if (event.getAction() == MotionEvent.ACTION_DOWN) { if (x >= buttonX && x <= buttonX + side && y >= buttonY && y <= buttonY + side) { buttonPressed = 1; @@ -220,7 +219,7 @@ public class ChatAudioCell extends ChatBaseCell implements SeekBar.SeekBarDelega public void updateButtonState() { String fileName = currentMessageObject.getFileName(); - File cacheFile = new File(Utilities.getCacheDir(), fileName); + File cacheFile = new File(AndroidUtilities.getCacheDir(), fileName); if (cacheFile.exists()) { MediaController.getInstance().removeLoadingFileObserver(this); boolean playing = MediaController.getInstance().isPlayingAudio(currentMessageObject); @@ -286,11 +285,11 @@ public class ChatAudioCell extends ChatBaseCell implements SeekBar.SeekBarDelega @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int width = MeasureSpec.getSize(widthMeasureSpec); - setMeasuredDimension(width, Utilities.dp(68)); + setMeasuredDimension(width, AndroidUtilities.dp(68)); if (isChat) { - backgroundWidth = Math.min(width - Utilities.dp(102), Utilities.dp(300)); + backgroundWidth = Math.min(width - AndroidUtilities.dp(102), AndroidUtilities.dp(300)); } else { - backgroundWidth = Math.min(width - Utilities.dp(50), Utilities.dp(300)); + backgroundWidth = Math.min(width - AndroidUtilities.dp(50), AndroidUtilities.dp(300)); } } @@ -299,33 +298,33 @@ public class ChatAudioCell extends ChatBaseCell implements SeekBar.SeekBarDelega super.onLayout(changed, left, top, right, bottom); if (currentMessageObject.isOut()) { - avatarImage.imageX = layoutWidth - backgroundWidth + Utilities.dp(9); - seekBarX = layoutWidth - backgroundWidth + Utilities.dp(97); - buttonX = layoutWidth - backgroundWidth + Utilities.dp(67); - timeX = layoutWidth - backgroundWidth + Utilities.dp(71); + avatarImage.imageX = layoutWidth - backgroundWidth + AndroidUtilities.dp(9); + seekBarX = layoutWidth - backgroundWidth + AndroidUtilities.dp(97); + buttonX = layoutWidth - backgroundWidth + AndroidUtilities.dp(67); + timeX = layoutWidth - backgroundWidth + AndroidUtilities.dp(71); } else { if (isChat) { - avatarImage.imageX = Utilities.dp(69); - seekBarX = Utilities.dp(158); - buttonX = Utilities.dp(128); - timeX = Utilities.dp(132); + avatarImage.imageX = AndroidUtilities.dp(69); + seekBarX = AndroidUtilities.dp(158); + buttonX = AndroidUtilities.dp(128); + timeX = AndroidUtilities.dp(132); } else { - avatarImage.imageX = Utilities.dp(16); - seekBarX = Utilities.dp(106); - buttonX = Utilities.dp(76); - timeX = Utilities.dp(80); + avatarImage.imageX = AndroidUtilities.dp(16); + seekBarX = AndroidUtilities.dp(106); + buttonX = AndroidUtilities.dp(76); + timeX = AndroidUtilities.dp(80); } } - avatarImage.imageY = Utilities.dp(9); - avatarImage.imageW = Utilities.dp(50); - avatarImage.imageH = Utilities.dp(50); + avatarImage.imageY = AndroidUtilities.dp(9); + avatarImage.imageW = AndroidUtilities.dp(50); + avatarImage.imageH = AndroidUtilities.dp(50); - seekBar.width = backgroundWidth - Utilities.dp(112); - seekBar.height = Utilities.dp(30); - progressView.width = backgroundWidth - Utilities.dp(136); - progressView.height = Utilities.dp(30); - seekBarY = Utilities.dp(13); - buttonY = Utilities.dp(10); + seekBar.width = backgroundWidth - AndroidUtilities.dp(112); + seekBar.height = AndroidUtilities.dp(30); + progressView.width = backgroundWidth - AndroidUtilities.dp(136); + progressView.height = AndroidUtilities.dp(30); + seekBarY = AndroidUtilities.dp(13); + buttonY = AndroidUtilities.dp(10); updateProgress(); } @@ -380,14 +379,14 @@ public class ChatAudioCell extends ChatBaseCell implements SeekBar.SeekBarDelega return; } - avatarImage.draw(canvas, avatarImage.imageX, avatarImage.imageY, Utilities.dp(50), Utilities.dp(50)); + avatarImage.draw(canvas, avatarImage.imageX, avatarImage.imageY, AndroidUtilities.dp(50), AndroidUtilities.dp(50)); canvas.save(); if (buttonState == 0 || buttonState == 1) { canvas.translate(seekBarX, seekBarY); seekBar.draw(canvas); } else { - canvas.translate(seekBarX + Utilities.dp(12), seekBarY); + canvas.translate(seekBarX + AndroidUtilities.dp(12), seekBarY); progressView.draw(canvas); } canvas.restore(); @@ -400,14 +399,14 @@ public class ChatAudioCell extends ChatBaseCell implements SeekBar.SeekBarDelega timePaint.setColor(0xff70b15c); } Drawable buttonDrawable = statesDrawable[state][buttonPressed]; - int side = Utilities.dp(36); + int side = AndroidUtilities.dp(36); int x = (side - buttonDrawable.getIntrinsicWidth()) / 2; int y = (side - buttonDrawable.getIntrinsicHeight()) / 2; setDrawableBounds(buttonDrawable, x + buttonX, y + buttonY); buttonDrawable.draw(canvas); canvas.save(); - canvas.translate(timeX, Utilities.dp(45)); + canvas.translate(timeX, AndroidUtilities.dp(45)); timeLayout.draw(canvas); canvas.restore(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatBaseCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatBaseCell.java index 552b411fc..d8f4aa583 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatBaseCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatBaseCell.java @@ -22,9 +22,10 @@ import android.view.MotionEvent; import android.view.SoundEffectConstants; import android.view.ViewConfiguration; -import org.telegram.messenger.LocaleController; +import org.telegram.android.AndroidUtilities; +import org.telegram.android.LocaleController; import org.telegram.messenger.TLRPC; -import org.telegram.messenger.MessagesController; +import org.telegram.android.MessagesController; import org.telegram.messenger.R; import org.telegram.messenger.Utilities; import org.telegram.objects.MessageObject; @@ -176,22 +177,22 @@ public class ChatBaseCell extends BaseCell { mediaBackgroundDrawable = getResources().getDrawable(R.drawable.phototime); timePaintIn = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); - timePaintIn.setTextSize(Utilities.dp(12)); + timePaintIn.setTextSize(AndroidUtilities.dp(12)); timePaintIn.setColor(0xffa1aab3); timePaintOut = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); - timePaintOut.setTextSize(Utilities.dp(12)); + timePaintOut.setTextSize(AndroidUtilities.dp(12)); timePaintOut.setColor(0xff70b15c); timeMediaPaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); - timeMediaPaint.setTextSize(Utilities.dp(12)); + timeMediaPaint.setTextSize(AndroidUtilities.dp(12)); timeMediaPaint.setColor(0xffffffff); namePaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); - namePaint.setTextSize(Utilities.dp(15)); + namePaint.setTextSize(AndroidUtilities.dp(15)); forwardNamePaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); - forwardNamePaint.setTextSize(Utilities.dp(14)); + forwardNamePaint.setTextSize(AndroidUtilities.dp(14)); } } @@ -286,11 +287,11 @@ public class ChatBaseCell extends BaseCell { currentNameString = Utilities.formatName(currentUser.first_name, currentUser.last_name); nameWidth = getMaxNameWidth(); - CharSequence nameStringFinal = TextUtils.ellipsize(currentNameString.replace("\n", " "), namePaint, nameWidth - Utilities.dp(12), TextUtils.TruncateAt.END); + CharSequence nameStringFinal = TextUtils.ellipsize(currentNameString.replace("\n", " "), namePaint, nameWidth - AndroidUtilities.dp(12), TextUtils.TruncateAt.END); nameLayout = new StaticLayout(nameStringFinal, namePaint, nameWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); if (nameLayout.getLineCount() > 0) { nameWidth = (int)Math.ceil(nameLayout.getLineWidth(0)); - namesOffset += Utilities.dp(18); + namesOffset += AndroidUtilities.dp(18); nameOffsetX = nameLayout.getLineLeft(0); } else { nameWidth = 0; @@ -308,12 +309,12 @@ public class ChatBaseCell extends BaseCell { forwardedNameWidth = getMaxNameWidth(); - CharSequence str = TextUtils.ellipsize(currentForwardNameString.replace("\n", " "), forwardNamePaint, forwardedNameWidth - Utilities.dp(40), TextUtils.TruncateAt.END); + CharSequence str = TextUtils.ellipsize(currentForwardNameString.replace("\n", " "), forwardNamePaint, forwardedNameWidth - AndroidUtilities.dp(40), TextUtils.TruncateAt.END); str = Html.fromHtml(String.format("%s
%s %s", LocaleController.getString("ForwardedMessage", R.string.ForwardedMessage), LocaleController.getString("From", R.string.From), str)); forwardedNameLayout = new StaticLayout(str, forwardNamePaint, forwardedNameWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); if (forwardedNameLayout.getLineCount() > 1) { forwardedNameWidth = Math.max((int) Math.ceil(forwardedNameLayout.getLineWidth(0)), (int) Math.ceil(forwardedNameLayout.getLineWidth(1))); - namesOffset += Utilities.dp(36); + namesOffset += AndroidUtilities.dp(36); forwardNameOffsetX = Math.min(forwardedNameLayout.getLineLeft(0), forwardedNameLayout.getLineLeft(1)); } else { forwardedNameWidth = 0; @@ -337,7 +338,7 @@ public class ChatBaseCell extends BaseCell { } protected int getMaxNameWidth() { - return backgroundWidth - Utilities.dp(8); + return backgroundWidth - AndroidUtilities.dp(8); } protected void startCheckLongPress() { @@ -372,7 +373,7 @@ public class ChatBaseCell extends BaseCell { avatarPressed = true; result = true; } else if (drawForwardedName && forwardedNameLayout != null) { - if (x >= forwardNameX && x <= forwardNameX + forwardedNameWidth && y >= forwardNameY && y <= forwardNameY + Utilities.dp(32)) { + if (x >= forwardNameX && x <= forwardNameX + forwardedNameWidth && y >= forwardNameY && y <= forwardNameY + AndroidUtilities.dp(32)) { forwardNamePressed = true; result = true; } @@ -409,7 +410,7 @@ public class ChatBaseCell extends BaseCell { } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { forwardNamePressed = false; } else if (event.getAction() == MotionEvent.ACTION_MOVE) { - if (!(x >= forwardNameX && x <= forwardNameX + forwardedNameWidth && y >= forwardNameY && y <= forwardNameY + Utilities.dp(32))) { + if (!(x >= forwardNameX && x <= forwardNameX + forwardedNameWidth && y >= forwardNameY && y <= forwardNameY + AndroidUtilities.dp(32))) { forwardNamePressed = false; } } @@ -433,23 +434,23 @@ public class ChatBaseCell extends BaseCell { timeLayout = new StaticLayout(currentTimeString, currentTimePaint, timeWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); if (!media) { if (!currentMessageObject.isOut()) { - timeX = backgroundWidth - Utilities.dp(9) - timeWidth + (isChat ? Utilities.dp(52) : 0); + timeX = backgroundWidth - AndroidUtilities.dp(9) - timeWidth + (isChat ? AndroidUtilities.dp(52) : 0); } else { - timeX = layoutWidth - timeWidth - Utilities.dpf(38.5f); + timeX = layoutWidth - timeWidth - AndroidUtilities.dpf(38.5f); } } else { if (!currentMessageObject.isOut()) { - timeX = backgroundWidth - Utilities.dp(4) - timeWidth + (isChat ? Utilities.dp(52) : 0); + timeX = backgroundWidth - AndroidUtilities.dp(4) - timeWidth + (isChat ? AndroidUtilities.dp(52) : 0); } else { - timeX = layoutWidth - timeWidth - Utilities.dpf(42.0f); + timeX = layoutWidth - timeWidth - AndroidUtilities.dpf(42.0f); } } if (isAvatarVisible) { - avatarImage.imageX = Utilities.dp(6); - avatarImage.imageY = layoutHeight - Utilities.dp(45); - avatarImage.imageW = Utilities.dp(42); - avatarImage.imageH = Utilities.dp(42); + avatarImage.imageX = AndroidUtilities.dp(6); + avatarImage.imageY = layoutHeight - AndroidUtilities.dp(45); + avatarImage.imageW = AndroidUtilities.dp(42); + avatarImage.imageH = AndroidUtilities.dp(42); } wasLayout = true; @@ -473,7 +474,7 @@ public class ChatBaseCell extends BaseCell { } if (isAvatarVisible) { - avatarImage.draw(canvas, Utilities.dp(6), layoutHeight - Utilities.dp(45), Utilities.dp(42), Utilities.dp(42)); + avatarImage.draw(canvas, AndroidUtilities.dp(6), layoutHeight - AndroidUtilities.dp(45), AndroidUtilities.dp(42), AndroidUtilities.dp(42)); } Drawable currentBackgroundDrawable = null; @@ -491,7 +492,7 @@ public class ChatBaseCell extends BaseCell { currentBackgroundDrawable = backgroundMediaDrawableOut; } } - setDrawableBounds(currentBackgroundDrawable, layoutWidth - backgroundWidth - (!media ? 0 : Utilities.dp(9)), Utilities.dp(1), backgroundWidth, layoutHeight - Utilities.dp(2)); + setDrawableBounds(currentBackgroundDrawable, layoutWidth - backgroundWidth - (!media ? 0 : AndroidUtilities.dp(9)), AndroidUtilities.dp(1), backgroundWidth, layoutHeight - AndroidUtilities.dp(2)); } else { if (isPressed() && isCheckPressed || !isCheckPressed && isPressed) { if (!media) { @@ -507,9 +508,9 @@ public class ChatBaseCell extends BaseCell { } } if (isChat) { - setDrawableBounds(currentBackgroundDrawable, Utilities.dp(52 + (!media ? 0 : 9)), Utilities.dp(1), backgroundWidth, layoutHeight - Utilities.dp(2)); + setDrawableBounds(currentBackgroundDrawable, AndroidUtilities.dp(52 + (!media ? 0 : 9)), AndroidUtilities.dp(1), backgroundWidth, layoutHeight - AndroidUtilities.dp(2)); } else { - setDrawableBounds(currentBackgroundDrawable, (!media ? 0 : Utilities.dp(9)), Utilities.dp(1), backgroundWidth, layoutHeight - Utilities.dp(2)); + setDrawableBounds(currentBackgroundDrawable, (!media ? 0 : AndroidUtilities.dp(9)), AndroidUtilities.dp(1), backgroundWidth, layoutHeight - AndroidUtilities.dp(2)); } } currentBackgroundDrawable.draw(canvas); @@ -518,7 +519,7 @@ public class ChatBaseCell extends BaseCell { if (drawName && nameLayout != null) { canvas.save(); - canvas.translate(currentBackgroundDrawable.getBounds().left + Utilities.dp(19) - nameOffsetX, Utilities.dp(10)); + canvas.translate(currentBackgroundDrawable.getBounds().left + AndroidUtilities.dp(19) - nameOffsetX, AndroidUtilities.dp(10)); namePaint.setColor(Utilities.getColorForId(currentUser.id)); nameLayout.draw(canvas); canvas.restore(); @@ -528,12 +529,12 @@ public class ChatBaseCell extends BaseCell { canvas.save(); if (currentMessageObject.isOut()) { forwardNamePaint.setColor(0xff4a923c); - forwardNameX = currentBackgroundDrawable.getBounds().left + Utilities.dp(10); - forwardNameY = Utilities.dp(10 + (drawName ? 18 : 0)); + forwardNameX = currentBackgroundDrawable.getBounds().left + AndroidUtilities.dp(10); + forwardNameY = AndroidUtilities.dp(10 + (drawName ? 18 : 0)); } else { forwardNamePaint.setColor(0xff006fc8); - forwardNameX = currentBackgroundDrawable.getBounds().left + Utilities.dp(19); - forwardNameY = Utilities.dp(10 + (drawName ? 18 : 0)); + forwardNameX = currentBackgroundDrawable.getBounds().left + AndroidUtilities.dp(19); + forwardNameY = AndroidUtilities.dp(10 + (drawName ? 18 : 0)); } canvas.translate(forwardNameX - forwardNameOffsetX, forwardNameY); forwardedNameLayout.draw(canvas); @@ -542,16 +543,16 @@ public class ChatBaseCell extends BaseCell { if (drawTime) { if (media) { - setDrawableBounds(mediaBackgroundDrawable, timeX - Utilities.dp(3), layoutHeight - Utilities.dpf(27.5f), timeWidth + Utilities.dp(6 + (currentMessageObject.isOut() ? 20 : 0)), Utilities.dpf(16.5f)); + setDrawableBounds(mediaBackgroundDrawable, timeX - AndroidUtilities.dp(3), layoutHeight - AndroidUtilities.dpf(27.5f), timeWidth + AndroidUtilities.dp(6 + (currentMessageObject.isOut() ? 20 : 0)), AndroidUtilities.dpf(16.5f)); mediaBackgroundDrawable.draw(canvas); canvas.save(); - canvas.translate(timeX, layoutHeight - Utilities.dpf(12.0f) - timeLayout.getHeight()); + canvas.translate(timeX, layoutHeight - AndroidUtilities.dpf(12.0f) - timeLayout.getHeight()); timeLayout.draw(canvas); canvas.restore(); } else { canvas.save(); - canvas.translate(timeX, layoutHeight - Utilities.dpf(6.5f) - timeLayout.getHeight()); + canvas.translate(timeX, layoutHeight - AndroidUtilities.dpf(6.5f) - timeLayout.getHeight()); timeLayout.draw(canvas); canvas.restore(); } @@ -586,45 +587,45 @@ public class ChatBaseCell extends BaseCell { if (drawClock) { if (!media) { - setDrawableBounds(clockDrawable, layoutWidth - Utilities.dpf(18.5f) - clockDrawable.getIntrinsicWidth(), layoutHeight - Utilities.dpf(8.5f) - clockDrawable.getIntrinsicHeight()); + setDrawableBounds(clockDrawable, layoutWidth - AndroidUtilities.dpf(18.5f) - clockDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dpf(8.5f) - clockDrawable.getIntrinsicHeight()); clockDrawable.draw(canvas); } else { - setDrawableBounds(clockMediaDrawable, layoutWidth - Utilities.dpf(22.0f) - clockMediaDrawable.getIntrinsicWidth(), layoutHeight - Utilities.dpf(13.0f) - clockMediaDrawable.getIntrinsicHeight()); + setDrawableBounds(clockMediaDrawable, layoutWidth - AndroidUtilities.dpf(22.0f) - clockMediaDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dpf(13.0f) - clockMediaDrawable.getIntrinsicHeight()); clockMediaDrawable.draw(canvas); } } if (drawCheck2) { if (!media) { if (drawCheck1) { - setDrawableBounds(checkDrawable, layoutWidth - Utilities.dpf(22.5f) - checkDrawable.getIntrinsicWidth(), layoutHeight - Utilities.dpf(8.5f) - checkDrawable.getIntrinsicHeight()); + setDrawableBounds(checkDrawable, layoutWidth - AndroidUtilities.dpf(22.5f) - checkDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dpf(8.5f) - checkDrawable.getIntrinsicHeight()); } else { - setDrawableBounds(checkDrawable, layoutWidth - Utilities.dpf(18.5f) - checkDrawable.getIntrinsicWidth(), layoutHeight - Utilities.dpf(8.5f) - checkDrawable.getIntrinsicHeight()); + setDrawableBounds(checkDrawable, layoutWidth - AndroidUtilities.dpf(18.5f) - checkDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dpf(8.5f) - checkDrawable.getIntrinsicHeight()); } checkDrawable.draw(canvas); } else { if (drawCheck1) { - setDrawableBounds(checkMediaDrawable, layoutWidth - Utilities.dpf(26.0f) - checkMediaDrawable.getIntrinsicWidth(), layoutHeight - Utilities.dpf(13.0f) - checkMediaDrawable.getIntrinsicHeight()); + setDrawableBounds(checkMediaDrawable, layoutWidth - AndroidUtilities.dpf(26.0f) - checkMediaDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dpf(13.0f) - checkMediaDrawable.getIntrinsicHeight()); } else { - setDrawableBounds(checkMediaDrawable, layoutWidth - Utilities.dpf(22.0f) - checkMediaDrawable.getIntrinsicWidth(), layoutHeight - Utilities.dpf(13.0f) - checkMediaDrawable.getIntrinsicHeight()); + setDrawableBounds(checkMediaDrawable, layoutWidth - AndroidUtilities.dpf(22.0f) - checkMediaDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dpf(13.0f) - checkMediaDrawable.getIntrinsicHeight()); } checkMediaDrawable.draw(canvas); } } if (drawCheck1) { if (!media) { - setDrawableBounds(halfCheckDrawable, layoutWidth - Utilities.dp(18) - halfCheckDrawable.getIntrinsicWidth(), layoutHeight - Utilities.dpf(8.5f) - halfCheckDrawable.getIntrinsicHeight()); + setDrawableBounds(halfCheckDrawable, layoutWidth - AndroidUtilities.dp(18) - halfCheckDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dpf(8.5f) - halfCheckDrawable.getIntrinsicHeight()); halfCheckDrawable.draw(canvas); } else { - setDrawableBounds(halfCheckMediaDrawable, layoutWidth - Utilities.dpf(20.5f) - halfCheckMediaDrawable.getIntrinsicWidth(), layoutHeight - Utilities.dpf(13.0f) - halfCheckMediaDrawable.getIntrinsicHeight()); + setDrawableBounds(halfCheckMediaDrawable, layoutWidth - AndroidUtilities.dpf(20.5f) - halfCheckMediaDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dpf(13.0f) - halfCheckMediaDrawable.getIntrinsicHeight()); halfCheckMediaDrawable.draw(canvas); } } if (drawError) { if (!media) { - setDrawableBounds(errorDrawable, layoutWidth - Utilities.dp(18) - errorDrawable.getIntrinsicWidth(), layoutHeight - Utilities.dpf(6.5f) - errorDrawable.getIntrinsicHeight()); + setDrawableBounds(errorDrawable, layoutWidth - AndroidUtilities.dp(18) - errorDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dpf(6.5f) - errorDrawable.getIntrinsicHeight()); errorDrawable.draw(canvas); } else { - setDrawableBounds(errorDrawable, layoutWidth - Utilities.dpf(20.5f) - errorDrawable.getIntrinsicWidth(), layoutHeight - Utilities.dpf(12.5f) - errorDrawable.getIntrinsicHeight()); + setDrawableBounds(errorDrawable, layoutWidth - AndroidUtilities.dpf(20.5f) - errorDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dpf(12.5f) - errorDrawable.getIntrinsicHeight()); errorDrawable.draw(canvas); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMediaCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMediaCell.java index 708c6f09d..a66e30850 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMediaCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMediaCell.java @@ -18,12 +18,12 @@ import android.text.StaticLayout; import android.text.TextPaint; import android.view.MotionEvent; import android.view.SoundEffectConstants; -import android.view.View; +import org.telegram.android.AndroidUtilities; import org.telegram.messenger.ConnectionsManager; import org.telegram.messenger.FileLoader; -import org.telegram.messenger.MediaController; -import org.telegram.messenger.MessagesController; +import org.telegram.android.MediaController; +import org.telegram.android.MessagesController; import org.telegram.messenger.R; import org.telegram.messenger.Utilities; import org.telegram.objects.MessageObject; @@ -34,7 +34,6 @@ import org.telegram.ui.Views.ImageReceiver; import org.telegram.ui.Views.ProgressView; import java.io.File; -import java.lang.ref.WeakReference; import java.util.Locale; public class ChatMediaCell extends ChatBaseCell implements MediaController.FileDownloadProgressListener { @@ -96,7 +95,7 @@ public class ChatMediaCell extends ChatBaseCell implements MediaController.FileD infoPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); infoPaint.setColor(0xffffffff); - infoPaint.setTextSize(Utilities.dp(12)); + infoPaint.setTextSize(AndroidUtilities.dp(12)); } TAG = MediaController.getInstance().generateObserverTag(); @@ -136,7 +135,7 @@ public class ChatMediaCell extends ChatBaseCell implements MediaController.FileD float y = event.getY(); boolean result = false; - int side = Utilities.dp(44); + int side = AndroidUtilities.dp(44); if (event.getAction() == MotionEvent.ACTION_DOWN) { if (delegate == null || delegate.canPerformActions()) { if (buttonState != -1 && x >= buttonX && x <= buttonX + side && y >= buttonY && y <= buttonY + side) { @@ -285,7 +284,7 @@ public class ChatMediaCell extends ChatBaseCell implements MediaController.FileD } double lat = object.messageOwner.media.geo.lat; double lon = object.messageOwner.media.geo._long; - String url = String.format(Locale.US, "https://maps.googleapis.com/maps/api/staticmap?center=%f,%f&zoom=13&size=100x100&maptype=roadmap&scale=%d&markers=color:red|size:big|%f,%f&sensor=false", lat, lon, Math.min(2, (int)Math.ceil(Utilities.density)), lat, lon); + String url = String.format(Locale.US, "https://maps.googleapis.com/maps/api/staticmap?center=%f,%f&zoom=13&size=100x100&maptype=roadmap&scale=%d&markers=color:red|size:big|%f,%f&sensor=false", lat, lon, Math.min(2, (int)Math.ceil(AndroidUtilities.density)), lat, lon); if (!url.equals(currentUrl)) { return true; } @@ -293,7 +292,7 @@ public class ChatMediaCell extends ChatBaseCell implements MediaController.FileD return true; } else if (currentPhotoObject != null && photoNotSet) { String fileName = MessageObject.getAttachFileName(currentPhotoObject.photoOwner); - File cacheFile = new File(Utilities.getCacheDir(), fileName); + File cacheFile = new File(AndroidUtilities.getCacheDir(), fileName); if (cacheFile.exists()) { return true; } @@ -330,7 +329,7 @@ public class ChatMediaCell extends ChatBaseCell implements MediaController.FileD String str = String.format("%d:%02d, %s", minutes, seconds, Utilities.formatFileSize(messageObject.messageOwner.media.video.size)); if (currentInfoString == null || !currentInfoString.equals(str)) { currentInfoString = str; - infoOffset = videoIconDrawable.getIntrinsicWidth() + Utilities.dp(4); + infoOffset = videoIconDrawable.getIntrinsicWidth() + AndroidUtilities.dp(4); infoWidth = (int) Math.ceil(infoPaint.measureText(currentInfoString)); infoLayout = new StaticLayout(currentInfoString, infoPaint, infoWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); } @@ -340,17 +339,17 @@ public class ChatMediaCell extends ChatBaseCell implements MediaController.FileD } if (messageObject.type == 4) { - photoWidth = Utilities.dp(100); - photoHeight = Utilities.dp(100); - backgroundWidth = photoWidth + Utilities.dp(12); + photoWidth = AndroidUtilities.dp(100); + photoHeight = AndroidUtilities.dp(100); + backgroundWidth = photoWidth + AndroidUtilities.dp(12); double lat = messageObject.messageOwner.media.geo.lat; double lon = messageObject.messageOwner.media.geo._long; - currentUrl = String.format(Locale.US, "https://maps.googleapis.com/maps/api/staticmap?center=%f,%f&zoom=13&size=100x100&maptype=roadmap&scale=%d&markers=color:red|size:big|%f,%f&sensor=false", lat, lon, Math.min(2, (int)Math.ceil(Utilities.density)), lat, lon); + currentUrl = String.format(Locale.US, "https://maps.googleapis.com/maps/api/staticmap?center=%f,%f&zoom=13&size=100x100&maptype=roadmap&scale=%d&markers=color:red|size:big|%f,%f&sensor=false", lat, lon, Math.min(2, (int)Math.ceil(AndroidUtilities.density)), lat, lon); photoImage.setImage(currentUrl, null, messageObject.isOut() ? placeholderOutDrawable : placeholderInDrawable); } else { - photoWidth = (int) (Math.min(Utilities.displaySize.x, Utilities.displaySize.y) * 0.7f); - photoHeight = photoWidth + Utilities.dp(100); + photoWidth = (int) (Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) * 0.7f); + photoHeight = photoWidth + AndroidUtilities.dp(100); if (photoWidth > 800) { photoWidth = 800; @@ -367,35 +366,35 @@ public class ChatMediaCell extends ChatBaseCell implements MediaController.FileD int h = (int) (currentPhotoObject.photoOwner.h / scale); if (w == 0) { if (messageObject.type == 3) { - w = infoWidth + infoOffset + Utilities.dp(16); + w = infoWidth + infoOffset + AndroidUtilities.dp(16); } else { - w = Utilities.dp(100); + w = AndroidUtilities.dp(100); } } if (h == 0) { - h = Utilities.dp(100); + h = AndroidUtilities.dp(100); } if (h > photoHeight) { float scale2 = h; h = photoHeight; scale2 /= h; w = (int) (w / scale2); - } else if (h < Utilities.dp(120)) { - h = Utilities.dp(120); + } else if (h < AndroidUtilities.dp(120)) { + h = AndroidUtilities.dp(120); float hScale = (float) currentPhotoObject.photoOwner.h / h; if (currentPhotoObject.photoOwner.w / hScale < photoWidth) { w = (int) (currentPhotoObject.photoOwner.w / hScale); } } - int timeWidthTotal = timeWidth + Utilities.dp(14 + (currentMessageObject.isOut() ? 20 : 0)); + int timeWidthTotal = timeWidth + AndroidUtilities.dp(14 + (currentMessageObject.isOut() ? 20 : 0)); if (w < timeWidthTotal) { w = timeWidthTotal; } photoWidth = w; photoHeight = h; - backgroundWidth = w + Utilities.dp(12); - currentPhotoFilter = String.format(Locale.US, "%d_%d", (int) (w / Utilities.density), (int) (h / Utilities.density)); + backgroundWidth = w + AndroidUtilities.dp(12); + currentPhotoFilter = String.format(Locale.US, "%d_%d", (int) (w / AndroidUtilities.density), (int) (h / AndroidUtilities.density)); if (currentPhotoObject.image != null) { photoImage.setImageBitmap(currentPhotoObject.image); @@ -403,7 +402,7 @@ public class ChatMediaCell extends ChatBaseCell implements MediaController.FileD boolean photoExist = true; String fileName = MessageObject.getAttachFileName(currentPhotoObject.photoOwner); if (messageObject.type == 1) { - File cacheFile = new File(Utilities.getCacheDir(), fileName); + File cacheFile = new File(AndroidUtilities.getCacheDir(), fileName); if (!cacheFile.exists()) { photoExist = false; } else { @@ -447,7 +446,7 @@ public class ChatMediaCell extends ChatBaseCell implements MediaController.FileD return; } fileName = MessageObject.getAttachFileName(currentPhotoObject.photoOwner); - cacheFile = new File(Utilities.getCacheDir(), fileName); + cacheFile = new File(AndroidUtilities.getCacheDir(), fileName); } else if (currentMessageObject.type == 8 || currentMessageObject.type == 3) { if (currentMessageObject.messageOwner.attachPath != null && currentMessageObject.messageOwner.attachPath.length() != 0) { File f = new File(currentMessageObject.messageOwner.attachPath); @@ -458,7 +457,7 @@ public class ChatMediaCell extends ChatBaseCell implements MediaController.FileD } if (fileName == null) { fileName = currentMessageObject.getFileName(); - cacheFile = new File(Utilities.getCacheDir(), fileName); + cacheFile = new File(AndroidUtilities.getCacheDir(), fileName); } } if (fileName == null) { @@ -525,7 +524,7 @@ public class ChatMediaCell extends ChatBaseCell implements MediaController.FileD @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), photoHeight + Utilities.dp(14)); + setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), photoHeight + AndroidUtilities.dp(14)); } @Override @@ -533,23 +532,23 @@ public class ChatMediaCell extends ChatBaseCell implements MediaController.FileD super.onLayout(changed, left, top, right, bottom); if (currentMessageObject.isOut()) { - photoImage.imageX = layoutWidth - backgroundWidth - Utilities.dp(3); + photoImage.imageX = layoutWidth - backgroundWidth - AndroidUtilities.dp(3); } else { if (isChat) { - photoImage.imageX = Utilities.dp(67); + photoImage.imageX = AndroidUtilities.dp(67); } else { - photoImage.imageX = Utilities.dp(15); + photoImage.imageX = AndroidUtilities.dp(15); } } - photoImage.imageY = Utilities.dp(7); + photoImage.imageY = AndroidUtilities.dp(7); photoImage.imageW = photoWidth; photoImage.imageH = photoHeight; - progressView.width = timeX - photoImage.imageX - Utilities.dpf(23.0f); - progressView.height = Utilities.dp(3); - progressView.progressHeight = Utilities.dp(3); + progressView.width = timeX - photoImage.imageX - AndroidUtilities.dpf(23.0f); + progressView.height = AndroidUtilities.dp(3); + progressView.progressHeight = AndroidUtilities.dp(3); - int size = Utilities.dp(44); + int size = AndroidUtilities.dp(44); buttonX = (int)(photoImage.imageX + (photoWidth - size) / 2.0f); buttonY = (int)(photoImage.imageY + (photoHeight - size) / 2.0f); } @@ -568,11 +567,11 @@ public class ChatMediaCell extends ChatBaseCell implements MediaController.FileD } if (progressVisible) { - setDrawableBounds(mediaBackgroundDrawable, photoImage.imageX + Utilities.dp(4), layoutHeight - Utilities.dpf(27.5f), progressView.width + Utilities.dp(12), Utilities.dpf(16.5f)); + setDrawableBounds(mediaBackgroundDrawable, photoImage.imageX + AndroidUtilities.dp(4), layoutHeight - AndroidUtilities.dpf(27.5f), progressView.width + AndroidUtilities.dp(12), AndroidUtilities.dpf(16.5f)); mediaBackgroundDrawable.draw(canvas); canvas.save(); - canvas.translate(photoImage.imageX + Utilities.dp(10), layoutHeight - Utilities.dpf(21.0f)); + canvas.translate(photoImage.imageX + AndroidUtilities.dp(10), layoutHeight - AndroidUtilities.dpf(21.0f)); progressView.draw(canvas); canvas.restore(); } @@ -584,16 +583,16 @@ public class ChatMediaCell extends ChatBaseCell implements MediaController.FileD } if (infoLayout != null && (buttonState == 1 || buttonState == 0 || buttonState == 3)) { - setDrawableBounds(mediaBackgroundDrawable, photoImage.imageX + Utilities.dp(4), photoImage.imageY + Utilities.dp(4), infoWidth + Utilities.dp(8) + infoOffset, Utilities.dpf(16.5f)); + setDrawableBounds(mediaBackgroundDrawable, photoImage.imageX + AndroidUtilities.dp(4), photoImage.imageY + AndroidUtilities.dp(4), infoWidth + AndroidUtilities.dp(8) + infoOffset, AndroidUtilities.dpf(16.5f)); mediaBackgroundDrawable.draw(canvas); if (currentMessageObject.type == 3) { - setDrawableBounds(videoIconDrawable, photoImage.imageX + Utilities.dp(8), photoImage.imageY + Utilities.dpf(7.5f)); + setDrawableBounds(videoIconDrawable, photoImage.imageX + AndroidUtilities.dp(8), photoImage.imageY + AndroidUtilities.dpf(7.5f)); videoIconDrawable.draw(canvas); } canvas.save(); - canvas.translate(photoImage.imageX + Utilities.dp(8) + infoOffset, photoImage.imageY + Utilities.dpf(5.5f)); + canvas.translate(photoImage.imageX + AndroidUtilities.dp(8) + infoOffset, photoImage.imageY + AndroidUtilities.dpf(5.5f)); infoLayout.draw(canvas); canvas.restore(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java index 9396d1aba..77786a70a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java @@ -14,8 +14,8 @@ import android.text.Spannable; import android.text.style.ClickableSpan; import android.view.MotionEvent; +import org.telegram.android.AndroidUtilities; import org.telegram.messenger.FileLog; -import org.telegram.messenger.Utilities; import org.telegram.objects.MessageObject; public class ChatMessageCell extends ChatBaseCell { @@ -132,10 +132,10 @@ public class ChatMessageCell extends ChatBaseCell { pressedLink = null; int maxWidth; if (isChat && !messageObject.isOut()) { - maxWidth = Utilities.displaySize.x - Utilities.dp(122); + maxWidth = AndroidUtilities.displaySize.x - AndroidUtilities.dp(122); drawName = true; } else { - maxWidth = Utilities.displaySize.x - Utilities.dp(80); + maxWidth = AndroidUtilities.displaySize.x - AndroidUtilities.dp(80); drawName = false; } @@ -144,25 +144,25 @@ public class ChatMessageCell extends ChatBaseCell { super.setMessageObject(messageObject); backgroundWidth = messageObject.textWidth; - totalHeight = messageObject.textHeight + Utilities.dpf(19.5f) + namesOffset; + totalHeight = messageObject.textHeight + AndroidUtilities.dpf(19.5f) + namesOffset; int maxChildWidth = Math.max(backgroundWidth, nameWidth); maxChildWidth = Math.max(maxChildWidth, forwardedNameWidth); - int timeMore = timeWidth + Utilities.dp(6); + int timeMore = timeWidth + AndroidUtilities.dp(6); if (messageObject.isOut()) { - timeMore += Utilities.dpf(20.5f); + timeMore += AndroidUtilities.dpf(20.5f); } if (maxWidth - messageObject.lastLineWidth < timeMore) { - totalHeight += Utilities.dp(14); - backgroundWidth = Math.max(maxChildWidth, messageObject.lastLineWidth) + Utilities.dp(29); + totalHeight += AndroidUtilities.dp(14); + backgroundWidth = Math.max(maxChildWidth, messageObject.lastLineWidth) + AndroidUtilities.dp(29); } else { int diff = maxChildWidth - messageObject.lastLineWidth; if (diff >= 0 && diff <= timeMore) { - backgroundWidth = maxChildWidth + timeMore - diff + Utilities.dp(29); + backgroundWidth = maxChildWidth + timeMore - diff + AndroidUtilities.dp(29); } else { - backgroundWidth = Math.max(maxChildWidth, messageObject.lastLineWidth + timeMore) + Utilities.dp(29); + backgroundWidth = Math.max(maxChildWidth, messageObject.lastLineWidth + timeMore) + AndroidUtilities.dp(29); } } } @@ -178,11 +178,11 @@ public class ChatMessageCell extends ChatBaseCell { super.onLayout(changed, left, top, right, bottom); if (currentMessageObject.isOut()) { - textX = layoutWidth - backgroundWidth + Utilities.dp(10); - textY = Utilities.dp(10) + namesOffset; + textX = layoutWidth - backgroundWidth + AndroidUtilities.dp(10); + textY = AndroidUtilities.dp(10) + namesOffset; } else { - textX = Utilities.dp(19) + (isChat ? Utilities.dp(52) : 0); - textY = Utilities.dp(10) + namesOffset; + textX = AndroidUtilities.dp(19) + (isChat ? AndroidUtilities.dp(52) : 0); + textY = AndroidUtilities.dp(10) + namesOffset; } } @@ -194,11 +194,11 @@ public class ChatMessageCell extends ChatBaseCell { } if (currentMessageObject.isOut()) { - textX = layoutWidth - backgroundWidth + Utilities.dp(10); - textY = Utilities.dp(10) + namesOffset; + textX = layoutWidth - backgroundWidth + AndroidUtilities.dp(10); + textY = AndroidUtilities.dp(10) + namesOffset; } else { - textX = Utilities.dp(19) + (isChat ? Utilities.dp(52) : 0); - textY = Utilities.dp(10) + namesOffset; + textX = AndroidUtilities.dp(19) + (isChat ? AndroidUtilities.dp(52) : 0); + textY = AndroidUtilities.dp(10) + namesOffset; } for (int a = firstVisibleBlockNum; a <= lastVisibleBlockNum; a++) { 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 3a6563775..1bf92a356 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatOrUserCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatOrUserCell.java @@ -17,11 +17,12 @@ import android.text.StaticLayout; import android.text.TextPaint; import android.text.TextUtils; +import org.telegram.android.AndroidUtilities; import org.telegram.PhoneFormat.PhoneFormat; -import org.telegram.messenger.LocaleController; +import org.telegram.android.LocaleController; import org.telegram.messenger.TLRPC; import org.telegram.messenger.ConnectionsManager; -import org.telegram.messenger.MessagesController; +import org.telegram.android.MessagesController; import org.telegram.messenger.R; import org.telegram.messenger.UserConfig; import org.telegram.messenger.Utilities; @@ -61,25 +62,25 @@ public class ChatOrUserCell extends BaseCell { private void init() { if (namePaint == null) { namePaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); - namePaint.setTextSize(Utilities.dp(18)); + namePaint.setTextSize(AndroidUtilities.dp(18)); namePaint.setColor(0xff222222); } if (nameEncryptedPaint == null) { nameEncryptedPaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); - nameEncryptedPaint.setTextSize(Utilities.dp(18)); + nameEncryptedPaint.setTextSize(AndroidUtilities.dp(18)); nameEncryptedPaint.setColor(0xff00a60e); } if (onlinePaint == null) { onlinePaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); - onlinePaint.setTextSize(Utilities.dp(15)); + onlinePaint.setTextSize(AndroidUtilities.dp(15)); onlinePaint.setColor(0xff316f9f); } if (offlinePaint == null) { offlinePaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); - offlinePaint.setTextSize(Utilities.dp(15)); + offlinePaint.setTextSize(AndroidUtilities.dp(15)); offlinePaint.setColor(0xff999999); } @@ -122,7 +123,7 @@ public class ChatOrUserCell extends BaseCell { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), Utilities.dp(64)); + setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), AndroidUtilities.dp(64)); } @Override @@ -243,14 +244,14 @@ public class ChatOrUserCell extends BaseCell { canvas.restore(); } - avatarImage.draw(canvas, cellLayout.avatarLeft, cellLayout.avatarTop, Utilities.dp(50), Utilities.dp(50)); + avatarImage.draw(canvas, cellLayout.avatarLeft, cellLayout.avatarTop, AndroidUtilities.dp(50), AndroidUtilities.dp(50)); if (useSeparator) { int h = getMeasuredHeight(); if (!usePadding) { canvas.drawLine(0, h - 1, getMeasuredWidth(), h, linePaint); } else { - canvas.drawLine(Utilities.dp(11), h - 1, getMeasuredWidth() - Utilities.dp(11), h, linePaint); + canvas.drawLine(AndroidUtilities.dp(11), h - 1, getMeasuredWidth() - AndroidUtilities.dp(11), h, linePaint); } } } @@ -262,14 +263,14 @@ public class ChatOrUserCell extends BaseCell { private StaticLayout nameLayout; private boolean drawNameLock; private int nameLockLeft; - private int nameLockTop = Utilities.dp(15); + private int nameLockTop = AndroidUtilities.dp(15); private int onlineLeft; - private int onlineTop = Utilities.dp(36); + private int onlineTop = AndroidUtilities.dp(36); private int onlineWidth; private StaticLayout onlineLayout; - private int avatarTop = Utilities.dp(7); + private int avatarTop = AndroidUtilities.dp(7); private int avatarLeft; public void build(int width, int height) { @@ -279,18 +280,18 @@ public class ChatOrUserCell extends BaseCell { if (encryptedChat != null) { drawNameLock = true; if (!LocaleController.isRTL) { - nameLockLeft = Utilities.dp(61 + (usePadding ? 11 : 0)); - nameLeft = Utilities.dp(65 + (usePadding ? 11 : 0)) + lockDrawable.getIntrinsicWidth(); + nameLockLeft = AndroidUtilities.dp(61 + (usePadding ? 11 : 0)); + nameLeft = AndroidUtilities.dp(65 + (usePadding ? 11 : 0)) + lockDrawable.getIntrinsicWidth(); } else { - nameLockLeft = width - Utilities.dp(63 + (usePadding ? 11 : 0)) - lockDrawable.getIntrinsicWidth(); - nameLeft = usePadding ? Utilities.dp(11) : 0; + nameLockLeft = width - AndroidUtilities.dp(63 + (usePadding ? 11 : 0)) - lockDrawable.getIntrinsicWidth(); + nameLeft = usePadding ? AndroidUtilities.dp(11) : 0; } } else { drawNameLock = false; if (!LocaleController.isRTL) { - nameLeft = Utilities.dp(61 + (usePadding ? 11 : 0)); + nameLeft = AndroidUtilities.dp(61 + (usePadding ? 11 : 0)); } else { - nameLeft = usePadding ? Utilities.dp(11) : 0; + nameLeft = usePadding ? AndroidUtilities.dp(11) : 0; } } @@ -319,22 +320,22 @@ public class ChatOrUserCell extends BaseCell { } if (!LocaleController.isRTL) { - onlineWidth = nameWidth = width - nameLeft - Utilities.dp(3 + (usePadding ? 11 : 0)); + onlineWidth = nameWidth = width - nameLeft - AndroidUtilities.dp(3 + (usePadding ? 11 : 0)); } else { - onlineWidth = nameWidth = width - nameLeft - Utilities.dp(61 + (usePadding ? 11 : 0)); + onlineWidth = nameWidth = width - nameLeft - AndroidUtilities.dp(61 + (usePadding ? 11 : 0)); } if (drawNameLock) { - nameWidth -= Utilities.dp(6) + lockDrawable.getIntrinsicWidth(); + nameWidth -= AndroidUtilities.dp(6) + lockDrawable.getIntrinsicWidth(); } - CharSequence nameStringFinal = TextUtils.ellipsize(nameString, currentNamePaint, nameWidth - Utilities.dp(12), TextUtils.TruncateAt.END); + CharSequence nameStringFinal = TextUtils.ellipsize(nameString, currentNamePaint, nameWidth - AndroidUtilities.dp(12), TextUtils.TruncateAt.END); nameLayout = new StaticLayout(nameStringFinal, currentNamePaint, nameWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); if (chat == null) { if (!LocaleController.isRTL) { - onlineLeft = Utilities.dp(61 + (usePadding ? 11 : 0)); + onlineLeft = AndroidUtilities.dp(61 + (usePadding ? 11 : 0)); } else { - onlineLeft = usePadding ? Utilities.dp(11) : 0; + onlineLeft = usePadding ? AndroidUtilities.dp(11) : 0; } String onlineString = ""; @@ -350,23 +351,23 @@ public class ChatOrUserCell extends BaseCell { } } - CharSequence onlineStringFinal = TextUtils.ellipsize(onlineString, currentOnlinePaint, nameWidth - Utilities.dp(12), TextUtils.TruncateAt.END); + CharSequence onlineStringFinal = TextUtils.ellipsize(onlineString, currentOnlinePaint, nameWidth - AndroidUtilities.dp(12), TextUtils.TruncateAt.END); onlineLayout = new StaticLayout(onlineStringFinal, currentOnlinePaint, nameWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); - nameTop = Utilities.dp(12); + nameTop = AndroidUtilities.dp(12); } else { onlineLayout = null; - nameTop = Utilities.dp(22); + nameTop = AndroidUtilities.dp(22); } if (!LocaleController.isRTL) { - avatarLeft = usePadding ? Utilities.dp(11) : 0; + avatarLeft = usePadding ? AndroidUtilities.dp(11) : 0; } else { - avatarLeft = width - Utilities.dp(50 + (usePadding ? 11 : 0)); + avatarLeft = width - AndroidUtilities.dp(50 + (usePadding ? 11 : 0)); } avatarImage.imageX = avatarLeft; avatarImage.imageY = avatarTop; - avatarImage.imageW = Utilities.dp(50); - avatarImage.imageH = Utilities.dp(50); + avatarImage.imageW = AndroidUtilities.dp(50); + avatarImage.imageH = AndroidUtilities.dp(50); double widthpx = 0; float left = 0; 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 b7a742c9d..25109034d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogCell.java @@ -17,12 +17,13 @@ import android.text.StaticLayout; import android.text.TextPaint; import android.text.TextUtils; +import org.telegram.android.AndroidUtilities; import org.telegram.PhoneFormat.PhoneFormat; -import org.telegram.messenger.LocaleController; +import org.telegram.android.LocaleController; import org.telegram.messenger.TLRPC; -import org.telegram.messenger.ContactsController; -import org.telegram.messenger.Emoji; -import org.telegram.messenger.MessagesController; +import org.telegram.android.ContactsController; +import org.telegram.android.Emoji; +import org.telegram.android.MessagesController; import org.telegram.messenger.R; import org.telegram.messenger.UserConfig; import org.telegram.messenger.Utilities; @@ -58,46 +59,46 @@ public class DialogCell extends BaseCell { private void init() { if (namePaint == null) { namePaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); - namePaint.setTextSize(Utilities.dp(19)); + namePaint.setTextSize(AndroidUtilities.dp(19)); namePaint.setColor(0xff222222); - namePaint.setTypeface(Utilities.getTypeface("fonts/rmedium.ttf")); + namePaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); } if (nameEncryptedPaint == null) { nameEncryptedPaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); - nameEncryptedPaint.setTextSize(Utilities.dp(19)); + nameEncryptedPaint.setTextSize(AndroidUtilities.dp(19)); nameEncryptedPaint.setColor(0xff00a60e); - nameEncryptedPaint.setTypeface(Utilities.getTypeface("fonts/rmedium.ttf")); + nameEncryptedPaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); } if (nameUnknownPaint == null) { nameUnknownPaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); - nameUnknownPaint.setTextSize(Utilities.dp(19)); + nameUnknownPaint.setTextSize(AndroidUtilities.dp(19)); nameUnknownPaint.setColor(0xff316f9f); - nameUnknownPaint.setTypeface(Utilities.getTypeface("fonts/rmedium.ttf")); + nameUnknownPaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); } if (messagePaint == null) { messagePaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); - messagePaint.setTextSize(Utilities.dp(16)); + messagePaint.setTextSize(AndroidUtilities.dp(16)); messagePaint.setColor(0xff808080); } if (messagePrintingPaint == null) { messagePrintingPaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); - messagePrintingPaint.setTextSize(Utilities.dp(16)); + messagePrintingPaint.setTextSize(AndroidUtilities.dp(16)); messagePrintingPaint.setColor(0xff316f9f); } if (timePaint == null) { timePaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); - timePaint.setTextSize(Utilities.dp(14)); + timePaint.setTextSize(AndroidUtilities.dp(14)); timePaint.setColor(0xff9e9e9e); } if (countPaint == null) { countPaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); - countPaint.setTextSize(Utilities.dp(13)); + countPaint.setTextSize(AndroidUtilities.dp(13)); countPaint.setColor(0xffffffff); } @@ -159,7 +160,7 @@ public class DialogCell extends BaseCell { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), Utilities.dp(70)); + setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), AndroidUtilities.dp(70)); } @Override @@ -309,20 +310,20 @@ public class DialogCell extends BaseCell { setDrawableBounds(errorDrawable, cellLayout.errorLeft, cellLayout.errorTop); errorDrawable.draw(canvas); } else if (cellLayout.drawCount) { - setDrawableBounds(countDrawable, cellLayout.countLeft - Utilities.dp(5), cellLayout.countTop, cellLayout.countWidth + Utilities.dp(10), countDrawable.getIntrinsicHeight()); + setDrawableBounds(countDrawable, cellLayout.countLeft - AndroidUtilities.dp(5), cellLayout.countTop, cellLayout.countWidth + AndroidUtilities.dp(10), countDrawable.getIntrinsicHeight()); countDrawable.draw(canvas); canvas.save(); - canvas.translate(cellLayout.countLeft, cellLayout.countTop + Utilities.dp(3)); + canvas.translate(cellLayout.countLeft, cellLayout.countTop + AndroidUtilities.dp(3)); cellLayout.countLayout.draw(canvas); canvas.restore(); } - avatarImage.draw(canvas, cellLayout.avatarLeft, cellLayout.avatarTop, Utilities.dp(54), Utilities.dp(54)); + avatarImage.draw(canvas, cellLayout.avatarLeft, cellLayout.avatarTop, AndroidUtilities.dp(54), AndroidUtilities.dp(54)); } private class DialogCellLayout { private int nameLeft; - private int nameTop = Utilities.dp(10); + private int nameTop = AndroidUtilities.dp(10); private int nameWidth; private StaticLayout nameLayout; private boolean drawNameLock; @@ -331,7 +332,7 @@ public class DialogCell extends BaseCell { private int nameLockTop; private int timeLeft; - private int timeTop = Utilities.dp(13); + private int timeTop = AndroidUtilities.dp(13); private int timeWidth; private StaticLayout timeLayout; @@ -339,25 +340,25 @@ public class DialogCell extends BaseCell { private boolean drawCheck2; private boolean drawClock; private int checkDrawLeft; - private int checkDrawTop = Utilities.dp(15); + private int checkDrawTop = AndroidUtilities.dp(15); private int halfCheckDrawLeft; - private int messageTop = Utilities.dp(40); + private int messageTop = AndroidUtilities.dp(40); private int messageLeft; private int messageWidth; private StaticLayout messageLayout; private boolean drawError; - private int errorTop = Utilities.dp(37); + private int errorTop = AndroidUtilities.dp(37); private int errorLeft; private boolean drawCount; - private int countTop = Utilities.dp(37); + private int countTop = AndroidUtilities.dp(37); private int countLeft; private int countWidth; private StaticLayout countLayout; - private int avatarTop = Utilities.dp(8); + private int avatarTop = AndroidUtilities.dp(8); private int avatarLeft; public void build(int width, int height) { @@ -374,32 +375,32 @@ public class DialogCell extends BaseCell { if (encryptedChat != null) { drawNameLock = true; drawNameGroup = false; - nameLockTop = Utilities.dp(13); + nameLockTop = AndroidUtilities.dp(13); if (!LocaleController.isRTL) { - nameLockLeft = Utilities.dp(77); - nameLeft = Utilities.dp(81) + lockDrawable.getIntrinsicWidth(); + nameLockLeft = AndroidUtilities.dp(77); + nameLeft = AndroidUtilities.dp(81) + lockDrawable.getIntrinsicWidth(); } else { - nameLockLeft = width - Utilities.dp(77) - lockDrawable.getIntrinsicWidth(); - nameLeft = Utilities.dp(14); + nameLockLeft = width - AndroidUtilities.dp(77) - lockDrawable.getIntrinsicWidth(); + nameLeft = AndroidUtilities.dp(14); } } else { drawNameLock = false; if (chat != null) { drawNameGroup = true; - nameLockTop = Utilities.dp(14); + nameLockTop = AndroidUtilities.dp(14); if (!LocaleController.isRTL) { - nameLockLeft = Utilities.dp(77); - nameLeft = Utilities.dp(81) + groupDrawable.getIntrinsicWidth(); + nameLockLeft = AndroidUtilities.dp(77); + nameLeft = AndroidUtilities.dp(81) + groupDrawable.getIntrinsicWidth(); } else { - nameLockLeft = width - Utilities.dp(77) - groupDrawable.getIntrinsicWidth(); - nameLeft = Utilities.dp(14); + nameLockLeft = width - AndroidUtilities.dp(77) - groupDrawable.getIntrinsicWidth(); + nameLeft = AndroidUtilities.dp(14); } } else { drawNameGroup = false; if (!LocaleController.isRTL) { - nameLeft = Utilities.dp(77); + nameLeft = AndroidUtilities.dp(77); } else { - nameLeft = Utilities.dp(14); + nameLeft = AndroidUtilities.dp(14); } } } @@ -476,10 +477,10 @@ public class DialogCell extends BaseCell { checkMessage = false; if (message.messageOwner.media != null && !(message.messageOwner.media instanceof TLRPC.TL_messageMediaEmpty)) { currentMessagePaint = messagePrintingPaint; - messageString = Emoji.replaceEmoji(Html.fromHtml(String.format("%s: %s", name, message.messageText)), messagePaint.getFontMetricsInt(), Utilities.dp(20)); + messageString = Emoji.replaceEmoji(Html.fromHtml(String.format("%s: %s", name, message.messageText)), messagePaint.getFontMetricsInt(), AndroidUtilities.dp(20)); } else { if (message.messageOwner.message != null) { - messageString = Emoji.replaceEmoji(Html.fromHtml(String.format("%s: %s", name, message.messageOwner.message.replace("\n", " ").replace("<", "<").replace(">", ">"))), messagePaint.getFontMetricsInt(), Utilities.dp(20)); + messageString = Emoji.replaceEmoji(Html.fromHtml(String.format("%s: %s", name, message.messageOwner.message.replace("\n", " ").replace("<", "<").replace(">", ">"))), messagePaint.getFontMetricsInt(), AndroidUtilities.dp(20)); } } } else { @@ -538,9 +539,9 @@ public class DialogCell extends BaseCell { timeWidth = (int)Math.ceil(timePaint.measureText(timeString)); timeLayout = new StaticLayout(timeString, timePaint, timeWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); if (!LocaleController.isRTL) { - timeLeft = width - Utilities.dp(11) - timeWidth; + timeLeft = width - AndroidUtilities.dp(11) - timeWidth; } else { - timeLeft = Utilities.dp(11); + timeLeft = AndroidUtilities.dp(11); } if (chat != null) { @@ -569,81 +570,81 @@ public class DialogCell extends BaseCell { } if (!LocaleController.isRTL) { - nameWidth = width - nameLeft - Utilities.dp(14) - timeWidth; + nameWidth = width - nameLeft - AndroidUtilities.dp(14) - timeWidth; } else { - nameWidth = width - nameLeft - Utilities.dp(77) - timeWidth; + nameWidth = width - nameLeft - AndroidUtilities.dp(77) - timeWidth; nameLeft += timeWidth; } if (drawNameLock) { - nameWidth -= Utilities.dp(4) + lockDrawable.getIntrinsicWidth(); + nameWidth -= AndroidUtilities.dp(4) + lockDrawable.getIntrinsicWidth(); } else if (drawNameGroup) { - nameWidth -= Utilities.dp(4) + groupDrawable.getIntrinsicWidth(); + nameWidth -= AndroidUtilities.dp(4) + groupDrawable.getIntrinsicWidth(); } if (drawClock) { - int w = clockDrawable.getIntrinsicWidth() + Utilities.dp(2); + int w = clockDrawable.getIntrinsicWidth() + AndroidUtilities.dp(2); nameWidth -= w; if (!LocaleController.isRTL) { checkDrawLeft = timeLeft - w; } else { - checkDrawLeft = timeLeft + timeWidth + Utilities.dp(2); + checkDrawLeft = timeLeft + timeWidth + AndroidUtilities.dp(2); nameLeft += w; } } else if (drawCheck2) { - int w = checkDrawable.getIntrinsicWidth() + Utilities.dp(2); + int w = checkDrawable.getIntrinsicWidth() + AndroidUtilities.dp(2); nameWidth -= w; if (drawCheck1) { - nameWidth -= halfCheckDrawable.getIntrinsicWidth() - Utilities.dp(5); + nameWidth -= halfCheckDrawable.getIntrinsicWidth() - AndroidUtilities.dp(5); if (!LocaleController.isRTL) { halfCheckDrawLeft = timeLeft - w; - checkDrawLeft = halfCheckDrawLeft - Utilities.dp(5); + checkDrawLeft = halfCheckDrawLeft - AndroidUtilities.dp(5); } else { - checkDrawLeft = timeLeft + timeWidth + Utilities.dp(2); - halfCheckDrawLeft = checkDrawLeft + Utilities.dp(5); - nameLeft += w + halfCheckDrawable.getIntrinsicWidth() - Utilities.dp(5); + checkDrawLeft = timeLeft + timeWidth + AndroidUtilities.dp(2); + halfCheckDrawLeft = checkDrawLeft + AndroidUtilities.dp(5); + nameLeft += w + halfCheckDrawable.getIntrinsicWidth() - AndroidUtilities.dp(5); } } else { if (!LocaleController.isRTL) { checkDrawLeft = timeLeft - w; } else { - checkDrawLeft = timeLeft + timeWidth + Utilities.dp(2); + checkDrawLeft = timeLeft + timeWidth + AndroidUtilities.dp(2); nameLeft += w; } } } - CharSequence nameStringFinal = TextUtils.ellipsize(nameString.replace("\n", " "), currentNamePaint, nameWidth - Utilities.dp(12), TextUtils.TruncateAt.END); + CharSequence nameStringFinal = TextUtils.ellipsize(nameString.replace("\n", " "), currentNamePaint, nameWidth - AndroidUtilities.dp(12), TextUtils.TruncateAt.END); nameLayout = new StaticLayout(nameStringFinal, currentNamePaint, nameWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); - messageWidth = width - Utilities.dp(88); + messageWidth = width - AndroidUtilities.dp(88); if (!LocaleController.isRTL) { - messageLeft = Utilities.dp(77); - avatarLeft = Utilities.dp(11); + messageLeft = AndroidUtilities.dp(77); + avatarLeft = AndroidUtilities.dp(11); } else { - messageLeft = Utilities.dp(11); - avatarLeft = width - Utilities.dp(65); + messageLeft = AndroidUtilities.dp(11); + avatarLeft = width - AndroidUtilities.dp(65); } avatarImage.imageX = avatarLeft; avatarImage.imageY = avatarTop; - avatarImage.imageW = Utilities.dp(54); - avatarImage.imageH = Utilities.dp(54); + avatarImage.imageW = AndroidUtilities.dp(54); + avatarImage.imageH = AndroidUtilities.dp(54); if (drawError) { - int w = errorDrawable.getIntrinsicWidth() + Utilities.dp(8); + int w = errorDrawable.getIntrinsicWidth() + AndroidUtilities.dp(8); messageWidth -= w; if (!LocaleController.isRTL) { - errorLeft = width - errorDrawable.getIntrinsicWidth() - Utilities.dp(11); + errorLeft = width - errorDrawable.getIntrinsicWidth() - AndroidUtilities.dp(11); } else { - errorLeft = Utilities.dp(11); + errorLeft = AndroidUtilities.dp(11); messageLeft += w; } } else if (countString != null) { - countWidth = Math.max(Utilities.dp(12), (int)Math.ceil(countPaint.measureText(countString))); + countWidth = Math.max(AndroidUtilities.dp(12), (int)Math.ceil(countPaint.measureText(countString))); countLayout = new StaticLayout(countString, countPaint, countWidth, Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false); - int w = countWidth + Utilities.dp(18); + int w = countWidth + AndroidUtilities.dp(18); messageWidth -= w; if (!LocaleController.isRTL) { - countLeft = width - countWidth - Utilities.dp(16); + countLeft = width - countWidth - AndroidUtilities.dp(16); } else { - countLeft = Utilities.dp(16); + countLeft = AndroidUtilities.dp(16); messageLeft += w; } drawCount = true; @@ -659,10 +660,10 @@ public class DialogCell extends BaseCell { if (mess.length() > 150) { mess = mess.substring(0, 150); } - messageString = Emoji.replaceEmoji(mess, messagePaint.getFontMetricsInt(), Utilities.dp(20)); + messageString = Emoji.replaceEmoji(mess, messagePaint.getFontMetricsInt(), AndroidUtilities.dp(20)); } - CharSequence messageStringFinal = TextUtils.ellipsize(messageString, currentMessagePaint, messageWidth - Utilities.dp(12), TextUtils.TruncateAt.END); + CharSequence messageStringFinal = TextUtils.ellipsize(messageString, currentMessagePaint, messageWidth - AndroidUtilities.dp(12), TextUtils.TruncateAt.END); messageLayout = new StaticLayout(messageStringFinal, currentMessagePaint, messageWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); double widthpx = 0; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java index 74f44d1f5..712c2cf5e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java @@ -8,7 +8,6 @@ package org.telegram.ui; -import android.animation.Animator; import android.app.Activity; import android.app.AlertDialog; import android.content.Context; @@ -26,54 +25,40 @@ import android.media.MediaPlayer; import android.media.ThumbnailUtils; import android.net.Uri; import android.os.Bundle; -import android.os.PowerManager; import android.provider.MediaStore; -import android.text.Editable; import android.text.Html; import android.text.TextUtils; -import android.text.TextWatcher; -import android.text.style.ImageSpan; import android.util.TypedValue; import android.view.Gravity; -import android.view.KeyEvent; import android.view.LayoutInflater; -import android.view.MotionEvent; -import android.view.Surface; import android.view.View; import android.view.ViewGroup; import android.view.ViewParent; import android.view.ViewTreeObserver; -import android.view.WindowManager; -import android.view.animation.AccelerateDecelerateInterpolator; -import android.view.inputmethod.EditorInfo; -import android.view.inputmethod.InputMethodManager; import android.webkit.MimeTypeMap; import android.widget.AbsListView; import android.widget.AdapterView; -import android.widget.EditText; import android.widget.FrameLayout; -import android.widget.ImageButton; import android.widget.ImageView; import android.widget.LinearLayout; -import android.widget.PopupWindow; import android.widget.ProgressBar; import android.widget.RelativeLayout; import android.widget.TextView; import android.widget.Toast; +import org.telegram.android.AndroidUtilities; import org.telegram.PhoneFormat.PhoneFormat; -import org.telegram.messenger.LocaleController; -import org.telegram.messenger.MediaController; -import org.telegram.messenger.MessagesStorage; +import org.telegram.android.LocaleController; +import org.telegram.android.MediaController; +import org.telegram.android.MessagesStorage; import org.telegram.messenger.TLRPC; -import org.telegram.messenger.ContactsController; +import org.telegram.android.ContactsController; import org.telegram.messenger.FileLog; import org.telegram.objects.MessageObject; import org.telegram.objects.PhotoObject; import org.telegram.messenger.ConnectionsManager; -import org.telegram.messenger.Emoji; import org.telegram.messenger.FileLoader; -import org.telegram.messenger.MessagesController; +import org.telegram.android.MessagesController; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.UserConfig; @@ -88,7 +73,7 @@ import org.telegram.ui.Views.ActionBar.ActionBarMenu; import org.telegram.ui.Views.ActionBar.ActionBarMenuItem; import org.telegram.ui.Views.BackupImageView; import org.telegram.ui.Views.ActionBar.BaseFragment; -import org.telegram.ui.Views.EmojiView; +import org.telegram.ui.Views.ChatActivityEnterView; import org.telegram.ui.Views.ImageReceiver; import org.telegram.ui.Views.LayoutListView; import org.telegram.ui.Views.MessageActionLayout; @@ -102,11 +87,10 @@ import java.util.Comparator; import java.util.HashMap; import java.util.concurrent.Semaphore; -public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLayout.SizeNotifierRelativeLayoutDelegate, - NotificationCenter.NotificationCenterDelegate, MessagesActivity.MessagesActivityDelegate, - DocumentSelectActivity.DocumentSelectActivityDelegate, PhotoViewer.PhotoViewerProvider, - PhotoPickerActivity.PhotoPickerActivityDelegate { +public class ChatActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate, MessagesActivity.MessagesActivityDelegate, + DocumentSelectActivity.DocumentSelectActivityDelegate, PhotoViewer.PhotoViewerProvider, PhotoPickerActivity.PhotoPickerActivityDelegate { + private ChatActivityEnterView chatActivityEnterView; private View timeItem; private View menuItem; private LayoutListView chatListView; @@ -115,26 +99,15 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa private TLRPC.User currentUser; private TLRPC.EncryptedChat currentEncryptedChat; private ChatAdapter chatAdapter; - private EditText messsageEditText; - private ImageButton sendButton; - private PopupWindow emojiPopup; - private ImageView emojiButton; - private EmojiView emojiView; - private View slideText; - private boolean keyboardVisible; - private int keyboardHeight = 0; - private int keyboardHeightLand = 0; + private View topPanel; private View secretChatPlaceholder; - private View contentView; private View progressView; - private boolean ignoreTextChange = false; private TextView emptyView; private View bottomOverlay; - private View recordPanel; - private TextView recordTimeText; + private TextView bottomOverlayText; - private ImageButton audioSendButton; + private MessageObject selectedObject; private MessageObject forwaringMessage; private TextView secretViewStatusTextView; @@ -142,7 +115,7 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa private TextView selectedMessagesCountTextView; private boolean paused = true; private boolean readWhenResume = false; - private boolean sendByEnter = false; + private int readWithDate = 0; private int readWithMid = 0; private boolean scrollToTopOnResume = false; @@ -154,7 +127,6 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa private View pagedownButton; private TextView topPanelText; private long dialog_id; - private SizeNotifierRelativeLayout sizeNotifierRelativeLayout; private HashMap selectedMessagesIds = new HashMap(); private HashMap selectedMessagesCanCopyIds = new HashMap(); @@ -167,7 +139,7 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa private boolean endReached = false; private boolean loading = false; private boolean cacheEndReaced = false; - private long lastTypingTimeSend = 0; + private int minDate = 0; private int progressTag = 0; boolean first = true; @@ -177,11 +149,6 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa private boolean unread_end_reached = true; private boolean loadingForward = false; private MessageObject unreadMessageObject = null; - private boolean recordingAudio = false; - private String lastTimeString = null; - private float startedDraggingX = -1; - private float distCanMove = Utilities.dp(80); - private PowerManager.WakeLock mWakeLock = null; private String currentPicturePath; @@ -317,6 +284,24 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa } else { return false; } + chatActivityEnterView = new ChatActivityEnterView(); + chatActivityEnterView.setDialogId(dialog_id); + chatActivityEnterView.setDelegate(new ChatActivityEnterView.ChatActivityEnterViewDelegate() { + @Override + public void onMessageSend() { + chatListView.post(new Runnable() { + @Override + public void run() { + chatListView.setSelectionFromTop(messages.size() - 1, -100000 - chatListView.getPaddingTop()); + } + }); + } + + @Override + public void needSendTyping() { + MessagesController.getInstance().sendTyping(dialog_id, classGuid); + } + }); NotificationCenter.getInstance().addObserver(this, MessagesController.messagesDidLoaded); NotificationCenter.getInstance().addObserver(this, 999); NotificationCenter.getInstance().addObserver(this, MessagesController.updateInterfaces); @@ -338,10 +323,6 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa NotificationCenter.getInstance().addObserver(this, FileLoader.FileLoadProgressChanged); NotificationCenter.getInstance().addObserver(this, MediaController.audioProgressDidChanged); NotificationCenter.getInstance().addObserver(this, MediaController.audioDidReset); - NotificationCenter.getInstance().addObserver(this, MediaController.recordProgressChanged); - NotificationCenter.getInstance().addObserver(this, MediaController.recordStarted); - NotificationCenter.getInstance().addObserver(this, MediaController.recordStartError); - NotificationCenter.getInstance().addObserver(this, MediaController.recordStopped); NotificationCenter.getInstance().addObserver(this, MediaController.screenshotTook); NotificationCenter.getInstance().addObserver(this, 997); @@ -350,7 +331,6 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa loading = true; MessagesController.getInstance().loadMessages(dialog_id, 0, 30, 0, true, 0, classGuid, true, false); SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); - sendByEnter = preferences.getBoolean("send_by_enter", false); if (currentChat != null) { downloadPhotos = preferences.getInt("photo_download_chat2", 0); @@ -369,6 +349,9 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa @Override public void onFragmentDestroy() { super.onFragmentDestroy(); + if (chatActivityEnterView != null) { + chatActivityEnterView.onDestroy(); + } NotificationCenter.getInstance().removeObserver(this, MessagesController.messagesDidLoaded); NotificationCenter.getInstance().removeObserver(this, 999); NotificationCenter.getInstance().removeObserver(this, MessagesController.updateInterfaces); @@ -390,29 +373,13 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa NotificationCenter.getInstance().removeObserver(this, MessagesController.contactsDidLoaded); NotificationCenter.getInstance().removeObserver(this, MediaController.audioProgressDidChanged); NotificationCenter.getInstance().removeObserver(this, MediaController.audioDidReset); - NotificationCenter.getInstance().removeObserver(this, MediaController.recordProgressChanged); - NotificationCenter.getInstance().removeObserver(this, MediaController.recordStarted); - NotificationCenter.getInstance().removeObserver(this, MediaController.recordStartError); - NotificationCenter.getInstance().removeObserver(this, MediaController.recordStopped); NotificationCenter.getInstance().removeObserver(this, MediaController.screenshotTook); NotificationCenter.getInstance().removeObserver(this, 997); if (currentEncryptedChat != null) { MediaController.getInstance().stopMediaObserver(); } - if (sizeNotifierRelativeLayout != null) { - sizeNotifierRelativeLayout.delegate = null; - sizeNotifierRelativeLayout = null; - } - if (mWakeLock != null) { - try { - mWakeLock.release(); - mWakeLock = null; - } catch (Exception e) { - FileLog.e("tmessages", e); - } - } - Utilities.unlockOrientation(getParentActivity()); + AndroidUtilities.unlockOrientation(getParentActivity()); MediaController.getInstance().stopAudio(); } @@ -561,7 +528,7 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa updateSubtitle(); if (currentEncryptedChat != null) { - actionBarLayer.setTitleIcon(R.drawable.ic_lock_white, Utilities.dp(4)); + actionBarLayer.setTitleIcon(R.drawable.ic_lock_white, AndroidUtilities.dp(4)); } ActionBarMenu menu = actionBarLayer.createMenu(); @@ -578,7 +545,6 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa item.addSubItem(attach_location, LocaleController.getString("ChatLocation", R.string.ChatLocation), R.drawable.ic_attach_location); menuItem = item; - ActionBarMenu actionMode = actionBarLayer.createActionMode(); actionMode.addItem(-2, R.drawable.ic_ab_done_gray); @@ -586,10 +552,10 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa layout.setBackgroundColor(0xffe5e5e5); actionMode.addView(layout); LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams)layout.getLayoutParams(); - layoutParams.width = Utilities.dp(1); + layoutParams.width = AndroidUtilities.dp(1); layoutParams.height = LinearLayout.LayoutParams.MATCH_PARENT; - layoutParams.topMargin = Utilities.dp(12); - layoutParams.bottomMargin = Utilities.dp(12); + layoutParams.topMargin = AndroidUtilities.dp(12); + layoutParams.bottomMargin = AndroidUtilities.dp(12); layoutParams.gravity = Gravity.CENTER_VERTICAL; layout.setLayoutParams(layoutParams); @@ -599,7 +565,7 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa selectedMessagesCountTextView.setSingleLine(true); selectedMessagesCountTextView.setLines(1); selectedMessagesCountTextView.setEllipsize(TextUtils.TruncateAt.END); - selectedMessagesCountTextView.setPadding(Utilities.dp(6), 0, 0, 0); + selectedMessagesCountTextView.setPadding(AndroidUtilities.dp(6), 0, 0, 0); selectedMessagesCountTextView.setGravity(Gravity.CENTER_VERTICAL); actionMode.addView(selectedMessagesCountTextView); layoutParams = (LinearLayout.LayoutParams)selectedMessagesCountTextView.getLayoutParams(); @@ -625,10 +591,7 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa fragmentView = inflater.inflate(R.layout.chat_layout, container, false); - sizeNotifierRelativeLayout = (SizeNotifierRelativeLayout)fragmentView.findViewById(R.id.chat_layout); - sizeNotifierRelativeLayout.delegate = this; - contentView = sizeNotifierRelativeLayout; - + View contentView = fragmentView.findViewById(R.id.chat_layout); emptyView = (TextView)fragmentView.findViewById(R.id.searchEmptyView); emptyView.setText(LocaleController.getString("NoMessages", R.string.NoMessages)); chatListView = (LayoutListView)fragmentView.findViewById(R.id.chat_list_view); @@ -641,9 +604,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); - recordPanel = fragmentView.findViewById(R.id.record_panel); - recordTimeText = (TextView)fragmentView.findViewById(R.id.recording_time_text); + View progressViewInner = progressView.findViewById(R.id.progressLayoutInner); updateContactStatus(); @@ -693,8 +654,8 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa } else { secretChatPlaceholder.setBackgroundResource(R.drawable.system_blue); } - secretViewStatusTextView = (TextView)contentView.findViewById(R.id.invite_text); - secretChatPlaceholder.setPadding(Utilities.dp(16), Utilities.dp(12), Utilities.dp(16), Utilities.dp(12)); + secretViewStatusTextView = (TextView) contentView.findViewById(R.id.invite_text); + secretChatPlaceholder.setPadding(AndroidUtilities.dp(16), AndroidUtilities.dp(12), AndroidUtilities.dp(16), AndroidUtilities.dp(12)); View v = contentView.findViewById(R.id.secret_placeholder); v.setVisibility(View.VISIBLE); @@ -723,7 +684,7 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa progressViewInner.setBackgroundResource(R.drawable.system_loader1); emptyView.setBackgroundResource(R.drawable.system_blue); } - emptyView.setPadding(Utilities.dp(7), Utilities.dp(1), Utilities.dp(7), Utilities.dp(1)); + emptyView.setPadding(AndroidUtilities.dp(7), AndroidUtilities.dp(1), AndroidUtilities.dp(7), AndroidUtilities.dp(1)); if (currentUser != null && currentUser.id / 1000 == 333) { emptyView.setText(LocaleController.getString("GotAQuestion", R.string.GotAQuestion)); @@ -783,12 +744,7 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa } }); - messsageEditText = (EditText)fragmentView.findViewById(R.id.chat_text_edit); - messsageEditText.setHint(LocaleController.getString("TypeMessage", R.string.TypeMessage)); - slideText = fragmentView.findViewById(R.id.slideText); - TextView textView = (TextView)fragmentView.findViewById(R.id.slideToCancelTextView); - textView.setText(LocaleController.getString("SlideToCancel", R.string.SlideToCancel)); - textView = (TextView)fragmentView.findViewById(R.id.bottom_overlay_chat_text); + TextView textView = (TextView)fragmentView.findViewById(R.id.bottom_overlay_chat_text); if (currentUser == null) { textView.setText(LocaleController.getString("DeleteThisGroup", R.string.DeleteThisGroup)); } else { @@ -805,11 +761,6 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa textView = (TextView)fragmentView.findViewById(R.id.secret_description4); textView.setText(LocaleController.getString("EncryptedDescription4", R.string.EncryptedDescription4)); - sendButton = (ImageButton)fragmentView.findViewById(R.id.chat_send_button); - sendButton.setEnabled(false); - sendButton.setVisibility(View.INVISIBLE); - emojiButton = (ImageView)fragmentView.findViewById(R.id.chat_smile_button); - if (loading && messages.isEmpty()) { progressView.setVisibility(View.VISIBLE); chatListView.setEmptyView(null); @@ -822,123 +773,6 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa } } - emojiButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - if (emojiPopup == null) { - showEmojiPopup(true); - } else { - showEmojiPopup(!emojiPopup.isShowing()); - } - } - }); - - messsageEditText.setOnKeyListener(new View.OnKeyListener() { - @Override - public boolean onKey(View view, int i, KeyEvent keyEvent) { - if (i == 4 && !keyboardVisible && emojiPopup != null && emojiPopup.isShowing()) { - if (keyEvent.getAction() == 1) { - showEmojiPopup(false); - } - return true; - } else if (i == KeyEvent.KEYCODE_ENTER && sendByEnter && keyEvent.getAction() == KeyEvent.ACTION_DOWN) { - sendMessage(); - return true; - } - return false; - } - }); - - messsageEditText.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - if (emojiPopup != null && emojiPopup.isShowing()) { - showEmojiPopup(false); - } - } - }); - - messsageEditText.setOnEditorActionListener(new TextView.OnEditorActionListener() { - @Override - public boolean onEditorAction(TextView textView, int i, KeyEvent keyEvent) { - if (i == EditorInfo.IME_ACTION_SEND) { - sendMessage(); - return true; - } else if (sendByEnter) { - if (keyEvent != null && i == EditorInfo.IME_NULL && keyEvent.getAction() == KeyEvent.ACTION_DOWN) { - sendMessage(); - return true; - } - } - return false; - } - }); - - sendButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - sendMessage(); - } - }); - - audioSendButton.setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(View view, MotionEvent motionEvent) { - if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) { - startedDraggingX = -1; - MediaController.getInstance().startRecording(dialog_id); - updateAudioRecordIntefrace(); - } else if (motionEvent.getAction() == MotionEvent.ACTION_UP || motionEvent.getAction() == MotionEvent.ACTION_CANCEL) { - startedDraggingX = -1; - MediaController.getInstance().stopRecording(true); - recordingAudio = false; - updateAudioRecordIntefrace(); - } else if (motionEvent.getAction() == MotionEvent.ACTION_MOVE && recordingAudio) { - float x = motionEvent.getX(); - if (x < -distCanMove) { - MediaController.getInstance().stopRecording(false); - recordingAudio = false; - updateAudioRecordIntefrace(); - } - if(android.os.Build.VERSION.SDK_INT > 13) { - x = x + audioSendButton.getX(); - FrameLayout.LayoutParams params = (FrameLayout.LayoutParams)slideText.getLayoutParams(); - if (startedDraggingX != -1) { - float dist = (x - startedDraggingX); - params.leftMargin = Utilities.dp(30) + (int)dist; - slideText.setLayoutParams(params); - float alpha = 1.0f + dist / distCanMove; - if (alpha > 1) { - alpha = 1; - } else if (alpha < 0) { - alpha = 0; - } - slideText.setAlpha(alpha); - } - if (x <= slideText.getX() + slideText.getWidth() + Utilities.dp(30)) { - if (startedDraggingX == -1) { - startedDraggingX = x; - distCanMove = (recordPanel.getMeasuredWidth() - slideText.getMeasuredWidth() - Utilities.dp(48)) / 2.0f; - if (distCanMove <= 0) { - distCanMove = Utilities.dp(80); - } else if (distCanMove > Utilities.dp(80)) { - distCanMove = Utilities.dp(80); - } - } - } - if (params.leftMargin > Utilities.dp(30)) { - params.leftMargin = Utilities.dp(30); - slideText.setLayoutParams(params); - slideText.setAlpha(1); - startedDraggingX = -1; - } - } - } - view.onTouchEvent(motionEvent); - return true; - } - }); - pagedownButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { @@ -946,49 +780,6 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa } }); - checkSendButton(); - - messsageEditText.addTextChangedListener(new TextWatcher() { - @Override - public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) { - - } - - @Override - public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) { - String message = getTrimmedString(charSequence.toString()); - sendButton.setEnabled(message.length() != 0); - checkSendButton(); - - if (message.length() != 0 && lastTypingTimeSend < System.currentTimeMillis() - 5000 && !ignoreTextChange) { - int currentTime = ConnectionsManager.getInstance().getCurrentTime(); - if (currentUser != null && currentUser.status != null && currentUser.status.expires < currentTime) { - return; - } - lastTypingTimeSend = System.currentTimeMillis(); - MessagesController.getInstance().sendTyping(dialog_id, classGuid); - } - } - - @Override - public void afterTextChanged(Editable editable) { - if (sendByEnter && editable.length() > 0 && editable.charAt(editable.length() - 1) == '\n') { - sendMessage(); - } - int i = 0; - ImageSpan[] arrayOfImageSpan = editable.getSpans(0, editable.length(), ImageSpan.class); - int j = arrayOfImageSpan.length; - while (true) { - if (i >= j) { - Emoji.replaceEmoji(editable, messsageEditText.getPaint().getFontMetricsInt(), Utilities.dp(20)); - return; - } - editable.removeSpan(arrayOfImageSpan[i]); - i++; - } - } - }); - bottomOverlayChat.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { @@ -1027,6 +818,8 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa } else { bottomOverlayChat.setVisibility(View.GONE); } + + chatActivityEnterView.setContainerView(getParentActivity(), fragmentView); } else { ViewGroup parent = (ViewGroup)fragmentView.getParent(); if (parent != null) { @@ -1036,125 +829,6 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa return fragmentView; } - private String getTrimmedString(String src) { - String result = src.trim(); - if (result.length() == 0) { - return result; - } - while (src.startsWith("\n")) { - src = src.substring(1); - } - while (src.endsWith("\n")) { - src = src.substring(0, src.length() - 1); - } - return src; - } - - private void checkSendButton() { - String message = getTrimmedString(messsageEditText.getText().toString()); - if (message.length() > 0) { - sendButton.setVisibility(View.VISIBLE); - audioSendButton.setVisibility(View.INVISIBLE); - } else { - sendButton.setVisibility(View.INVISIBLE); - audioSendButton.setVisibility(View.VISIBLE); - } - } - - private void updateAudioRecordIntefrace() { - if (recordingAudio) { - try { - if (mWakeLock == null) { - PowerManager pm = (PowerManager) ApplicationLoader.applicationContext.getSystemService(Context.POWER_SERVICE); - mWakeLock = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE, "audio record lock"); - mWakeLock.acquire(); - } - } catch (Exception e) { - FileLog.e("tmessages", e); - } - Utilities.lockOrientation(getParentActivity()); - - recordPanel.setVisibility(View.VISIBLE); - recordTimeText.setText("00:00"); - lastTimeString = null; - if(android.os.Build.VERSION.SDK_INT > 13) { - FrameLayout.LayoutParams params = (FrameLayout.LayoutParams)slideText.getLayoutParams(); - params.leftMargin = Utilities.dp(30); - slideText.setLayoutParams(params); - slideText.setAlpha(1); - recordPanel.setX(Utilities.displaySize.x); - recordPanel.animate().setInterpolator(new AccelerateDecelerateInterpolator()).setListener(new Animator.AnimatorListener() { - @Override - public void onAnimationStart(Animator animator) { - } - - @Override - public void onAnimationEnd(Animator animator) { - recordPanel.setX(0); - } - - @Override - public void onAnimationCancel(Animator animator) { - } - - @Override - public void onAnimationRepeat(Animator animator) { - } - }).setDuration(300).translationX(0).start(); - } - } else { - if (mWakeLock != null) { - try { - mWakeLock.release(); - mWakeLock = null; - } catch (Exception e) { - FileLog.e("tmessages", e); - } - } - Utilities.unlockOrientation(getParentActivity()); - if(android.os.Build.VERSION.SDK_INT > 13) { - recordPanel.animate().setInterpolator(new AccelerateDecelerateInterpolator()).setListener(new Animator.AnimatorListener() { - @Override - public void onAnimationStart(Animator animator) { - - } - - @Override - public void onAnimationEnd(Animator animator) { - FrameLayout.LayoutParams params = (FrameLayout.LayoutParams)slideText.getLayoutParams(); - params.leftMargin = Utilities.dp(30); - slideText.setLayoutParams(params); - slideText.setAlpha(1); - recordPanel.setVisibility(View.GONE); - } - - @Override - public void onAnimationCancel(Animator animator) { - } - - @Override - public void onAnimationRepeat(Animator animator) { - } - }).setDuration(300).translationX(Utilities.displaySize.x).start(); - } else { - recordPanel.setVisibility(View.GONE); - } - } - } - - private void sendMessage() { - if (processSendingText(messsageEditText.getText().toString())) { - messsageEditText.setText(""); - lastTypingTimeSend = 0; - chatListView.post(new Runnable() { - @Override - public void run() { - chatListView.setSelectionFromTop(messages.size() - 1, -100000 - chatListView.getPaddingTop()); - } - }); - } - } - private void scrollToLastMessage() { if (unread_end_reached || first_unread_id == 0) { chatListView.setSelectionFromTop(messages.size() - 1, -100000 - chatListView.getPaddingTop()); @@ -1235,8 +909,8 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa bottomOverlay.setVisibility(View.GONE); } if (hideKeyboard) { - hideEmojiPopup(); - Utilities.hideKeyboard(getParentActivity().getCurrentFocus()); + chatActivityEnterView.hideEmojiPopup(); + AndroidUtilities.hideKeyboard(getParentActivity().getCurrentFocus()); } checkActionBarMenu(); } @@ -1393,7 +1067,7 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa } } if (!canSave) { - File f = new File(Utilities.getCacheDir(), messageObject.getFileName()); + File f = new File(AndroidUtilities.getCacheDir(), messageObject.getFileName()); if (f.exists()) { canSave = true; } @@ -1437,7 +1111,7 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa } } if (!canSave) { - File f = new File(Utilities.getCacheDir(), messageObject.getFileName()); + File f = new File(AndroidUtilities.getCacheDir(), messageObject.getFileName()); if (f.exists()) { canSave = true; } @@ -1584,57 +1258,6 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa } } - @Override - public void onSizeChanged(int height) { - Rect localRect = new Rect(); - getParentActivity().getWindow().getDecorView().getWindowVisibleDisplayFrame(localRect); - - WindowManager manager = (WindowManager) ApplicationLoader.applicationContext.getSystemService(Activity.WINDOW_SERVICE); - if (manager == null || manager.getDefaultDisplay() == null) { - return; - } - int rotation = manager.getDefaultDisplay().getRotation(); - - if (height > Utilities.dp(50)) { - if (rotation == Surface.ROTATION_270 || rotation == Surface.ROTATION_90) { - keyboardHeightLand = height; - ApplicationLoader.applicationContext.getSharedPreferences("emoji", 0).edit().putInt("kbd_height_land3", keyboardHeightLand).commit(); - } else { - keyboardHeight = height; - ApplicationLoader.applicationContext.getSharedPreferences("emoji", 0).edit().putInt("kbd_height", keyboardHeight).commit(); - } - } - - if (emojiPopup != null && emojiPopup.isShowing()) { - WindowManager wm = (WindowManager) ApplicationLoader.applicationContext.getSystemService(Context.WINDOW_SERVICE); - final WindowManager.LayoutParams layoutParams = (WindowManager.LayoutParams)emojiPopup.getContentView().getLayoutParams(); - layoutParams.width = contentView.getWidth(); - if (rotation == Surface.ROTATION_270 || rotation == Surface.ROTATION_90) { - layoutParams.height = keyboardHeightLand; - } else { - layoutParams.height = keyboardHeight; - } - wm.updateViewLayout(emojiPopup.getContentView(), layoutParams); - if (!keyboardVisible) { - contentView.post(new Runnable() { - @Override - public void run() { - contentView.setPadding(0, 0, 0, layoutParams.height); - contentView.requestLayout(); - } - }); - } - } - - boolean oldValue = keyboardVisible; - keyboardVisible = height > 0; - if (keyboardVisible && contentView.getPaddingBottom() > 0) { - showEmojiPopup(false); - } else if (!keyboardVisible && keyboardVisible != oldValue && emojiPopup != null && emojiPopup.isShowing()) { - showEmojiPopup(false); - } - } - @Override public void onActivityResultFragment(int requestCode, int resultCode, Intent data) { if (resultCode == Activity.RESULT_OK) { @@ -1723,16 +1346,7 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa } public boolean processSendingText(String text) { - text = getTrimmedString(text); - if (text.length() != 0) { - int count = (int)Math.ceil(text.length() / 2048.0f); - for (int a = 0; a < count; a++) { - String mess = text.substring(a * 2048, Math.min((a + 1) * 2048, text.length())); - MessagesController.getInstance().sendMessage(mess, dialog_id); - } - return true; - } - return false; + return chatActivityEnterView.processSendingText(text); } public void processSendingPhoto(String imageFilePath, Uri imageUri) { @@ -1958,6 +1572,7 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa video = new TLRPC.TL_video(); video.thumb = size; video.caption = ""; + video.mime_type = "video/mp4"; video.id = 0; File temp = new File(videoPath); if (temp != null && temp.exists()) { @@ -2136,18 +1751,20 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa chatAdapter.notifyDataSetChanged(); if (positionToUnread && unreadMessageObject != null) { if (messages.get(messages.size() - 1) == unreadMessageObject) { - chatListView.setSelectionFromTop(0, Utilities.dp(-11)); + chatListView.setSelectionFromTop(0, AndroidUtilities.dp(-11)); } else { - chatListView.setSelectionFromTop(messages.size() - messages.indexOf(unreadMessageObject), Utilities.dp(-11)); + chatListView.setSelectionFromTop(messages.size() - messages.indexOf(unreadMessageObject), AndroidUtilities.dp(-11)); } ViewTreeObserver obs = chatListView.getViewTreeObserver(); obs.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { - if (messages.get(messages.size() - 1) == unreadMessageObject) { - chatListView.setSelectionFromTop(0, Utilities.dp(-11)); - } else { - chatListView.setSelectionFromTop(messages.size() - messages.indexOf(unreadMessageObject), Utilities.dp(-11)); + if (!messages.isEmpty()) { + if (messages.get(messages.size() - 1) == unreadMessageObject) { + chatListView.setSelectionFromTop(0, AndroidUtilities.dp(-11)); + } else { + chatListView.setSelectionFromTop(messages.size() - messages.indexOf(unreadMessageObject), AndroidUtilities.dp(-11)); + } } chatListView.getViewTreeObserver().removeOnPreDrawListener(this); return false; @@ -2212,9 +1829,6 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa if (chatListView != null) { chatListView.invalidateViews(); } - if (emojiView != null) { - emojiView.invalidateViews(); - } } 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 || (updateMask & MessagesController.UPDATE_MASK_CHAT_MEMBERS) != 0) { @@ -2392,9 +2006,6 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa } } } else if (id == MessagesController.closeChats) { - if (messsageEditText != null && messsageEditText.isFocused()) { - Utilities.hideKeyboard(messsageEditText); - } removeSelfFromStack(); } else if (id == MessagesController.messagesReaded) { ArrayList markAsReadMessages = (ArrayList)args[0]; @@ -2591,14 +2202,6 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa } } } - } else if (id == MediaController.recordProgressChanged) { - Long time = (Long)args[0] / 1000; - String str = String.format("%02d:%02d", time / 60, time % 60); - if (lastTimeString == null || !lastPrintString.equals(str)) { - if (recordTimeText != null) { - recordTimeText.setText(str); - } - } } else if (id == MessagesController.removeAllMessagesFromDialog) { messages.clear(); messagesByDays.clear(); @@ -2622,16 +2225,6 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa selectedMessagesCanCopyIds.clear(); actionBarLayer.hideActionMode(); chatAdapter.notifyDataSetChanged(); - } else if (id == MediaController.recordStartError || id == MediaController.recordStopped) { - if (recordingAudio) { - recordingAudio = false; - updateAudioRecordIntefrace(); - } - } else if (id == MediaController.recordStarted) { - if (!recordingAudio) { - recordingAudio = true; - updateAudioRecordIntefrace(); - } } else if (id == MediaController.screenshotTook) { updateInformationForScreenshotDetector(); } @@ -2658,7 +2251,7 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa topPanel.setVisibility(View.GONE); } else { topPanel.setVisibility(View.VISIBLE); - topPanelText.setShadowLayer(1, 0, Utilities.dp(1), 0xff8797a3); + topPanelText.setShadowLayer(1, 0, AndroidUtilities.dp(1), 0xff8797a3); if (isCustomTheme) { topPlaneClose.setImageResource(R.drawable.ic_msg_btn_cross_custom); topPanel.setBackgroundResource(R.drawable.top_pane_custom); @@ -2727,82 +2320,6 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa } } - private void createEmojiPopup() { - if (getParentActivity() == null) { - return; - } - emojiView = new EmojiView(getParentActivity()); - emojiView.setListener(new EmojiView.Listener() { - public void onBackspace() { - messsageEditText.dispatchKeyEvent(new KeyEvent(0, 67)); - } - - public void onEmojiSelected(String paramAnonymousString) { - int i = messsageEditText.getSelectionEnd(); - CharSequence localCharSequence = Emoji.replaceEmoji(paramAnonymousString, messsageEditText.getPaint().getFontMetricsInt(), Utilities.dp(20)); - messsageEditText.setText(messsageEditText.getText().insert(i, localCharSequence)); - int j = i + localCharSequence.length(); - messsageEditText.setSelection(j, j); - } - }); - emojiPopup = new PopupWindow(emojiView); - } - - private void showEmojiPopup(boolean show) { - InputMethodManager localInputMethodManager = (InputMethodManager)ApplicationLoader.applicationContext.getSystemService(Context.INPUT_METHOD_SERVICE); - if (show) { - if (emojiPopup == null) { - createEmojiPopup(); - } - int currentHeight; - WindowManager manager = (WindowManager) ApplicationLoader.applicationContext.getSystemService(Activity.WINDOW_SERVICE); - int rotation = manager.getDefaultDisplay().getRotation(); - if (keyboardHeight <= 0) { - keyboardHeight = ApplicationLoader.applicationContext.getSharedPreferences("emoji", 0).getInt("kbd_height", Utilities.dp(200)); - } - if (keyboardHeightLand <= 0) { - keyboardHeightLand = ApplicationLoader.applicationContext.getSharedPreferences("emoji", 0).getInt("kbd_height_land3", Utilities.dp(200)); - } - if (rotation == Surface.ROTATION_270 || rotation == Surface.ROTATION_90) { - currentHeight = keyboardHeightLand; - } else { - currentHeight = keyboardHeight; - } - emojiPopup.setHeight(View.MeasureSpec.makeMeasureSpec(currentHeight, View.MeasureSpec.EXACTLY)); - emojiPopup.setWidth(View.MeasureSpec.makeMeasureSpec(contentView.getWidth(), View.MeasureSpec.EXACTLY)); - - emojiPopup.showAtLocation(getParentActivity().getWindow().getDecorView(), 83, 0, 0); - if (!keyboardVisible) { - contentView.setPadding(0, 0, 0, currentHeight); - emojiButton.setImageResource(R.drawable.ic_msg_panel_hide); - return; - } - emojiButton.setImageResource(R.drawable.ic_msg_panel_kb); - return; - } - if (emojiButton != null) { - emojiButton.setImageResource(R.drawable.ic_msg_panel_smiles); - } - if (emojiPopup != null) { - emojiPopup.dismiss(); - } - if (contentView != null) { - contentView.post(new Runnable() { - public void run() { - if (contentView != null) { - contentView.setPadding(0, 0, 0, 0); - } - } - }); - } - } - - public void hideEmojiPopup() { - if (emojiPopup != null && emojiPopup.isShowing()) { - showEmojiPopup(false); - } - } - @Override public void onResume() { super.onResume(); @@ -2815,7 +2332,7 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa if (scrollToTopOnResume) { if (scrollToTopUnReadOnResume && unreadMessageObject != null) { if (chatListView != null) { - chatListView.setSelectionFromTop(messages.size() - messages.indexOf(unreadMessageObject), -chatListView.getPaddingTop() - Utilities.dp(7)); + chatListView.setSelectionFromTop(messages.size() - messages.indexOf(unreadMessageObject), -chatListView.getPaddingTop() - AndroidUtilities.dp(7)); } } else { if (chatListView != null) { @@ -2838,21 +2355,9 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa SharedPreferences.Editor editor = preferences.edit(); editor.remove("dialog_" + dialog_id); editor.commit(); - ignoreTextChange = true; - messsageEditText.setText(lastMessageText); - messsageEditText.setSelection(messsageEditText.getText().length()); - ignoreTextChange = false; - } - if (messsageEditText != null) { - messsageEditText.postDelayed(new Runnable() { - @Override - public void run() { - if (messsageEditText != null) { - messsageEditText.requestFocus(); - } - } - }, 400); + chatActivityEnterView.setFieldText(lastMessageText); } + chatActivityEnterView.setFieldFocused(true); if (currentEncryptedChat != null) { chatEnterTime = System.currentTimeMillis(); chatLeaveTime = 0; @@ -2878,7 +2383,7 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa @Override public void onBeginSlide() { super.onBeginSlide(); - hideEmojiPopup(); + chatActivityEnterView.hideEmojiPopup(); } private void setTypingAnimation(boolean start) { @@ -2888,9 +2393,9 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa if (start) { try { if (currentChat != null) { - actionBarLayer.setSubTitleIcon(R.drawable.typing_dots_chat, Utilities.dp(4)); + actionBarLayer.setSubTitleIcon(R.drawable.typing_dots_chat, AndroidUtilities.dp(4)); } else { - actionBarLayer.setSubTitleIcon(R.drawable.typing_dots, Utilities.dp(4)); + actionBarLayer.setSubTitleIcon(R.drawable.typing_dots, AndroidUtilities.dp(4)); } AnimationDrawable mAnim = (AnimationDrawable)actionBarLayer.getSubTitleIcon(); mAnim.setAlpha(200); @@ -2907,21 +2412,24 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa public void onPause() { super.onPause(); actionBarLayer.hideActionMode(); - hideEmojiPopup(); + chatActivityEnterView.hideEmojiPopup(); paused = true; MessagesController.getInstance().openned_dialog_id = 0; - if (messsageEditText != null && messsageEditText.length() != 0) { + String text = chatActivityEnterView.getFieldText(); + if (text != null) { SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); SharedPreferences.Editor editor = preferences.edit(); - editor.putString("dialog_" + dialog_id, messsageEditText.getText().toString()); + editor.putString("dialog_" + dialog_id, text); editor.commit(); } - if (currentEncryptedChat != null) { + chatActivityEnterView.setFieldFocused(false); + + /*if (currentEncryptedChat != null) { disabled chatLeaveTime = System.currentTimeMillis(); updateInformationForScreenshotDetector(); - } + }*/ } private void updateInformationForScreenshotDetector() { @@ -2961,9 +2469,9 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa if (getParentActivity() == null) { return true; } - int height = Utilities.dp(48); + int height = AndroidUtilities.dp(48); if (!Utilities.isTablet(getParentActivity()) && getParentActivity().getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) { - height = Utilities.dp(40); + height = AndroidUtilities.dp(40); selectedMessagesCountTextView.setTextSize(16); } else { selectedMessagesCountTextView.setTextSize(18); @@ -3168,7 +2676,7 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa } } if (locFile == null) { - File f = new File(Utilities.getCacheDir(), selectedObject.getFileName()); + File f = new File(AndroidUtilities.getCacheDir(), selectedObject.getFileName()); if (f.exists()) { locFile = f; } @@ -3379,8 +2887,8 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa actionBarLayer.hideActionMode(); updateVisibleRows(); return false; - } else if (emojiPopup != null && emojiPopup.isShowing()) { - hideEmojiPopup(); + } else if (chatActivityEnterView.isEmojiPopupShowing()) { + chatActivityEnterView.hideEmojiPopup(); return false; } return true; @@ -3469,16 +2977,16 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa if (!disableSelection) { 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); + holder.chatBubbleView.setPadding(AndroidUtilities.dp(6), AndroidUtilities.dp(6), AndroidUtilities.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); + holder.chatBubbleView.setPadding(AndroidUtilities.dp(15), AndroidUtilities.dp(6), AndroidUtilities.dp(9), 0); } else if (messageType == 8) { holder.chatBubbleView.setBackgroundResource(R.drawable.chat_outgoing_text_states); - holder.chatBubbleView.setPadding(Utilities.dp(9), Utilities.dp(9), Utilities.dp(18), 0); + holder.chatBubbleView.setPadding(AndroidUtilities.dp(9), AndroidUtilities.dp(9), AndroidUtilities.dp(18), 0); } else if (messageType == 9) { holder.chatBubbleView.setBackgroundResource(R.drawable.chat_incoming_text_states); - holder.chatBubbleView.setPadding(Utilities.dp(18), Utilities.dp(9), Utilities.dp(9), 0); + holder.chatBubbleView.setPadding(AndroidUtilities.dp(18), AndroidUtilities.dp(9), AndroidUtilities.dp(9), 0); } } else { if (messageType == 12) { @@ -3487,28 +2995,28 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa } else { holder.chatBubbleView.setBackgroundResource(R.drawable.msg_out); } - holder.chatBubbleView.setPadding(Utilities.dp(6), Utilities.dp(6), Utilities.dp(18), 0); + holder.chatBubbleView.setPadding(AndroidUtilities.dp(6), AndroidUtilities.dp(6), AndroidUtilities.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); + holder.chatBubbleView.setPadding(AndroidUtilities.dp(15), AndroidUtilities.dp(6), AndroidUtilities.dp(9), 0); } else if (messageType == 8) { 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); + holder.chatBubbleView.setPadding(AndroidUtilities.dp(9), AndroidUtilities.dp(9), AndroidUtilities.dp(18), 0); } else if (messageType == 9) { 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.setPadding(AndroidUtilities.dp(18), AndroidUtilities.dp(9), AndroidUtilities.dp(9), 0); } } } @@ -3563,7 +3071,7 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa view.getLocationInWindow(coords); PhotoViewer.PlaceProviderObject object = new PhotoViewer.PlaceProviderObject(); object.viewX = coords[0]; - object.viewY = coords[1] - Utilities.statusBarHeight; + object.viewY = coords[1] - AndroidUtilities.statusBarHeight; object.parentView = chatListView; object.imageReceiver = imageReceiver; object.thumb = object.imageReceiver.getBitmap(); @@ -3761,7 +3269,7 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa f = new File(message.messageOwner.attachPath); } if (f == null || f != null && !f.exists()) { - f = new File(Utilities.getCacheDir(), message.getFileName()); + f = new File(AndroidUtilities.getCacheDir(), message.getFileName()); } Intent intent = new Intent(Intent.ACTION_VIEW); intent.setDataAndType(Uri.fromFile(f), "video/mp4"); @@ -3890,7 +3398,7 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa } if (type == 11 || type == 10) { - int width = Utilities.displaySize.x - Utilities.dp(30); + int width = AndroidUtilities.displaySize.x - AndroidUtilities.dp(30); messageTextView.setText(message.messageText); messageTextView.setMaxWidth(width); @@ -3898,7 +3406,7 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa if (message.messageOwner.action instanceof TLRPC.TL_messageActionUserUpdatedPhoto) { photoImage.setImage(message.messageOwner.action.newUserPhoto.photo_small, "50_50", Utilities.getUserAvatarForId(currentUser.id)); } else { - PhotoObject photo = PhotoObject.getClosestImageWithSize(message.photoThumbs, Utilities.dp(64), Utilities.dp(64)); + PhotoObject photo = PhotoObject.getClosestImageWithSize(message.photoThumbs, AndroidUtilities.dp(64), AndroidUtilities.dp(64)); if (photo != null) { if (photo.image != null) { photoImage.setImageBitmap(photo.image); @@ -4093,7 +3601,7 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa } if (load && message.messageOwner.attachPath != null && message.messageOwner.attachPath.length() != 0 || !load && (message.messageOwner.attachPath == null || message.messageOwner.attachPath.length() == 0)) { File cacheFile = null; - if ((cacheFile = new File(Utilities.getCacheDir(), fileName)).exists()) { + if ((cacheFile = new File(AndroidUtilities.getCacheDir(), fileName)).exists()) { if (actionAttachButton != null) { actionAttachButton.setVisibility(View.VISIBLE); if (message.type == 8 || message.type == 9) { @@ -4141,15 +3649,15 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa int width; if (currentChat != null && type != 8) { if (actionView.getVisibility() == View.VISIBLE) { - width = Utilities.displaySize.x - Utilities.dp(290); + width = AndroidUtilities.displaySize.x - AndroidUtilities.dp(290); } else { - width = Utilities.displaySize.x - Utilities.dp(270); + width = AndroidUtilities.displaySize.x - AndroidUtilities.dp(270); } } else { if (actionView.getVisibility() == View.VISIBLE) { - width = Utilities.displaySize.x - Utilities.dp(240); + width = AndroidUtilities.displaySize.x - AndroidUtilities.dp(240); } else { - width = Utilities.displaySize.x - Utilities.dp(220); + width = AndroidUtilities.displaySize.x - AndroidUtilities.dp(220); } } nameTextView.setMaxWidth(width); @@ -4393,7 +3901,7 @@ public class ChatActivity extends BaseFragment implements SizeNotifierRelativeLa f = new File(message.messageOwner.attachPath); } if (f == null || f != null && !f.exists()) { - f = new File(Utilities.getCacheDir(), fileName); + f = new File(AndroidUtilities.getCacheDir(), fileName); } if (f != null && f.exists()) { String realMimeType = null; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatProfileActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatProfileActivity.java index 5647e0d07..6eb1d792f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatProfileActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatProfileActivity.java @@ -23,12 +23,13 @@ import android.widget.ImageButton; import android.widget.ListView; import android.widget.TextView; -import org.telegram.messenger.LocaleController; -import org.telegram.messenger.MessagesStorage; +import org.telegram.android.AndroidUtilities; +import org.telegram.android.LocaleController; +import org.telegram.android.MessagesStorage; import org.telegram.messenger.TLRPC; import org.telegram.messenger.ConnectionsManager; import org.telegram.messenger.FileLog; -import org.telegram.messenger.MessagesController; +import org.telegram.android.MessagesController; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.UserConfig; @@ -299,7 +300,7 @@ public class ChatProfileActivity extends BaseFragment implements NotificationCen avatarImage.getLocationInWindow(coords); PhotoViewer.PlaceProviderObject object = new PhotoViewer.PlaceProviderObject(); object.viewX = coords[0]; - object.viewY = coords[1] - Utilities.statusBarHeight; + object.viewY = coords[1] - AndroidUtilities.statusBarHeight; object.parentView = listView; object.imageReceiver = avatarImage.imageReceiver; object.thumb = object.imageReceiver.getBitmap(); @@ -596,7 +597,7 @@ public class ChatProfileActivity extends BaseFragment implements NotificationCen avatarImage = (BackupImageView)view.findViewById(R.id.settings_avatar_image); avatarImage.processDetach = false; TextView textView = (TextView)view.findViewById(R.id.settings_name); - Typeface typeface = Utilities.getTypeface("fonts/rmedium.ttf"); + Typeface typeface = AndroidUtilities.getTypeface("fonts/rmedium.ttf"); textView.setTypeface(typeface); textView.setText(chat.title); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatProfileChangeNameActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatProfileChangeNameActivity.java index 1902d8fb2..2b204a9dd 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatProfileChangeNameActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatProfileChangeNameActivity.java @@ -20,11 +20,11 @@ import android.widget.Button; import android.widget.EditText; import android.widget.TextView; -import org.telegram.messenger.LocaleController; +import org.telegram.android.AndroidUtilities; +import org.telegram.android.LocaleController; import org.telegram.messenger.TLRPC; -import org.telegram.messenger.MessagesController; +import org.telegram.android.MessagesController; import org.telegram.messenger.R; -import org.telegram.messenger.Utilities; import org.telegram.ui.Views.ActionBar.BaseFragment; public class ChatProfileChangeNameActivity extends BaseFragment { @@ -108,14 +108,14 @@ public class ChatProfileChangeNameActivity extends BaseFragment { boolean animations = preferences.getBoolean("view_animations", true); if (!animations) { firstNameField.requestFocus(); - Utilities.showKeyboard(firstNameField); + AndroidUtilities.showKeyboard(firstNameField); } } @Override public void onOpenAnimationEnd() { firstNameField.requestFocus(); - Utilities.showKeyboard(firstNameField); + AndroidUtilities.showKeyboard(firstNameField); } private void saveName() { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ContactAddActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ContactAddActivity.java index b0ff3c5c5..3ffe51631 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ContactAddActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ContactAddActivity.java @@ -21,11 +21,12 @@ import android.widget.Button; import android.widget.EditText; import android.widget.TextView; +import org.telegram.android.AndroidUtilities; import org.telegram.PhoneFormat.PhoneFormat; -import org.telegram.messenger.ContactsController; -import org.telegram.messenger.LocaleController; +import org.telegram.android.ContactsController; +import org.telegram.android.LocaleController; import org.telegram.messenger.TLRPC; -import org.telegram.messenger.MessagesController; +import org.telegram.android.MessagesController; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.Utilities; @@ -104,7 +105,7 @@ public class ContactAddActivity extends BaseFragment implements NotificationCent avatarImage = (BackupImageView)fragmentView.findViewById(R.id.settings_avatar_image); avatarImage.processDetach = false; phoneText = (TextView)fragmentView.findViewById(R.id.settings_name); - Typeface typeface = Utilities.getTypeface("fonts/rmedium.ttf"); + Typeface typeface = AndroidUtilities.getTypeface("fonts/rmedium.ttf"); phoneText.setTypeface(typeface); firstNameField = (EditText)fragmentView.findViewById(R.id.first_name_field); @@ -183,13 +184,13 @@ public class ContactAddActivity extends BaseFragment implements NotificationCent boolean animations = preferences.getBoolean("view_animations", true); if (!animations) { firstNameField.requestFocus(); - Utilities.showKeyboard(firstNameField); + AndroidUtilities.showKeyboard(firstNameField); } } @Override public void onOpenAnimationEnd() { firstNameField.requestFocus(); - Utilities.showKeyboard(firstNameField); + AndroidUtilities.showKeyboard(firstNameField); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ContactsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ContactsActivity.java index 5d1e82f1f..a67f82d9b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ContactsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ContactsActivity.java @@ -23,13 +23,14 @@ import android.widget.AdapterView; import android.widget.EditText; import android.widget.TextView; -import org.telegram.messenger.LocaleController; +import org.telegram.android.AndroidUtilities; +import org.telegram.android.LocaleController; import org.telegram.messenger.TLObject; import org.telegram.messenger.TLRPC; import org.telegram.messenger.ConnectionsManager; -import org.telegram.messenger.ContactsController; +import org.telegram.android.ContactsController; import org.telegram.messenger.FileLog; -import org.telegram.messenger.MessagesController; +import org.telegram.android.MessagesController; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.RPCRequest; @@ -148,9 +149,9 @@ public class ContactsActivity extends BaseFragment implements NotificationCenter listView.setAdapter(listViewAdapter); listViewAdapter.notifyDataSetChanged(); if (!LocaleController.isRTL) { - listView.setPadding(Utilities.dp(16), listView.getPaddingTop(), Utilities.dp(30), listView.getPaddingBottom()); + listView.setPadding(AndroidUtilities.dp(16), listView.getPaddingTop(), AndroidUtilities.dp(30), listView.getPaddingBottom()); } else { - listView.setPadding(Utilities.dp(30), listView.getPaddingTop(), Utilities.dp(16), listView.getPaddingBottom()); + listView.setPadding(AndroidUtilities.dp(30), listView.getPaddingTop(), AndroidUtilities.dp(16), listView.getPaddingBottom()); } if (android.os.Build.VERSION.SDK_INT >= 11) { listView.setFastScrollAlwaysVisible(true); @@ -170,7 +171,7 @@ public class ContactsActivity extends BaseFragment implements NotificationCenter if (text.length() != 0) { searchWas = true; if (listView != null) { - listView.setPadding(Utilities.dp(16), listView.getPaddingTop(), Utilities.dp(16), listView.getPaddingBottom()); + listView.setPadding(AndroidUtilities.dp(16), listView.getPaddingTop(), AndroidUtilities.dp(16), listView.getPaddingBottom()); listView.setAdapter(searchListViewAdapter); searchListViewAdapter.notifyDataSetChanged(); if(android.os.Build.VERSION.SDK_INT >= 11) { @@ -320,7 +321,7 @@ public class ContactsActivity extends BaseFragment implements NotificationCenter @Override public void onScrollStateChanged(AbsListView absListView, int i) { if (i == SCROLL_STATE_TOUCH_SCROLL && searching && searchWas) { - Utilities.hideKeyboard(getParentActivity().getCurrentFocus()); + AndroidUtilities.hideKeyboard(getParentActivity().getCurrentFocus()); } } @@ -419,7 +420,7 @@ public class ContactsActivity extends BaseFragment implements NotificationCenter } } } - }, null, true, RPCRequest.RPCRequestClassGeneric | RPCRequest.RPCRequestClassFailOnServerErrors); + }, true, RPCRequest.RPCRequestClassGeneric | RPCRequest.RPCRequestClassFailOnServerErrors); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/CountrySelectActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/CountrySelectActivity.java index 86c3d7eb4..3303a31bd 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/CountrySelectActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/CountrySelectActivity.java @@ -18,8 +18,9 @@ import android.widget.BaseAdapter; import android.widget.EditText; import android.widget.TextView; +import org.telegram.android.AndroidUtilities; import org.telegram.messenger.FileLog; -import org.telegram.messenger.LocaleController; +import org.telegram.android.LocaleController; import org.telegram.messenger.R; import org.telegram.messenger.Utilities; import org.telegram.ui.Adapters.BaseFragmentAdapter; @@ -147,9 +148,9 @@ public class CountrySelectActivity extends BaseFragment { ViewGroup group = (ViewGroup) listView.getParent(); listView.setAdapter(listViewAdapter); if (!LocaleController.isRTL) { - listView.setPadding(Utilities.dp(16), listView.getPaddingTop(), Utilities.dp(30), listView.getPaddingBottom()); + listView.setPadding(AndroidUtilities.dp(16), listView.getPaddingTop(), AndroidUtilities.dp(30), listView.getPaddingBottom()); } else { - listView.setPadding(Utilities.dp(30), listView.getPaddingTop(), Utilities.dp(16), listView.getPaddingBottom()); + listView.setPadding(AndroidUtilities.dp(30), listView.getPaddingTop(), AndroidUtilities.dp(16), listView.getPaddingBottom()); } if (android.os.Build.VERSION.SDK_INT >= 11) { listView.setFastScrollAlwaysVisible(true); @@ -167,7 +168,7 @@ public class CountrySelectActivity extends BaseFragment { if (text.length() != 0) { searchWas = true; if (listView != null) { - listView.setPadding(Utilities.dp(16), listView.getPaddingTop(), Utilities.dp(16), listView.getPaddingBottom()); + listView.setPadding(AndroidUtilities.dp(16), listView.getPaddingTop(), AndroidUtilities.dp(16), listView.getPaddingBottom()); listView.setAdapter(searchListViewAdapter); if(android.os.Build.VERSION.SDK_INT >= 11) { listView.setFastScrollAlwaysVisible(false); @@ -228,7 +229,7 @@ public class CountrySelectActivity extends BaseFragment { @Override public void onScrollStateChanged(AbsListView absListView, int i) { if (i == SCROLL_STATE_TOUCH_SCROLL && searching && searchWas) { - Utilities.hideKeyboard(getParentActivity().getCurrentFocus()); + AndroidUtilities.hideKeyboard(getParentActivity().getCurrentFocus()); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/DocumentSelectActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/DocumentSelectActivity.java index a869af45f..784963d5e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/DocumentSelectActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/DocumentSelectActivity.java @@ -24,7 +24,7 @@ import android.widget.ListView; import android.widget.TextView; import org.telegram.messenger.FileLog; -import org.telegram.messenger.LocaleController; +import org.telegram.android.LocaleController; import org.telegram.messenger.R; import org.telegram.messenger.Utilities; import org.telegram.ui.Adapters.BaseFragmentAdapter; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateActivity.java index 1192082d0..28e7f77e8 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateActivity.java @@ -32,13 +32,14 @@ import android.widget.EditText; import android.widget.ImageView; import android.widget.TextView; +import org.telegram.android.AndroidUtilities; import org.telegram.PhoneFormat.PhoneFormat; -import org.telegram.messenger.LocaleController; +import org.telegram.android.LocaleController; import org.telegram.messenger.TLRPC; import org.telegram.messenger.ConnectionsManager; -import org.telegram.messenger.ContactsController; +import org.telegram.android.ContactsController; import org.telegram.messenger.FileLog; -import org.telegram.messenger.MessagesController; +import org.telegram.android.MessagesController; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.UserConfig; @@ -72,7 +73,7 @@ public class GroupCreateActivity extends BaseFragment implements NotificationCen int sz = super.getSize(paint, text, start, end, fm); - int offset = Utilities.dp(6); + int offset = AndroidUtilities.dp(6); int w = (fm.bottom - fm.top) / 2; fm.top = -w - offset; fm.bottom = w - offset; @@ -293,7 +294,7 @@ public class GroupCreateActivity extends BaseFragment implements NotificationCen @Override public void onScrollStateChanged(AbsListView absListView, int i) { if (i == SCROLL_STATE_TOUCH_SCROLL) { - Utilities.hideKeyboard(userSelectEditText); + AndroidUtilities.hideKeyboard(userSelectEditText); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateFinalActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateFinalActivity.java index da86a8149..ff2380ce2 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateFinalActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateFinalActivity.java @@ -22,11 +22,11 @@ import android.widget.ImageButton; import android.widget.TextView; import org.telegram.messenger.ConnectionsManager; -import org.telegram.messenger.LocaleController; -import org.telegram.messenger.MessagesStorage; +import org.telegram.android.LocaleController; +import org.telegram.android.MessagesStorage; import org.telegram.messenger.TLRPC; import org.telegram.messenger.FileLog; -import org.telegram.messenger.MessagesController; +import org.telegram.android.MessagesController; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.Utilities; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/IdenticonActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/IdenticonActivity.java index f3010c792..b18e9909e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/IdenticonActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/IdenticonActivity.java @@ -20,11 +20,11 @@ import android.view.WindowManager; import android.widget.LinearLayout; import android.widget.TextView; -import org.telegram.messenger.LocaleController; +import org.telegram.android.AndroidUtilities; +import org.telegram.android.LocaleController; import org.telegram.messenger.TLRPC; -import org.telegram.messenger.MessagesController; +import org.telegram.android.MessagesController; import org.telegram.messenger.R; -import org.telegram.messenger.Utilities; import org.telegram.ui.Views.ActionBar.ActionBarLayer; import org.telegram.ui.Views.ActionBar.BaseFragment; import org.telegram.ui.Views.IdenticonView; @@ -48,7 +48,7 @@ public class IdenticonActivity extends BaseFragment { actionBarLayer.setDisplayHomeAsUpEnabled(true, R.drawable.ic_ab_back); actionBarLayer.setBackOverlay(R.layout.updating_state_layout); actionBarLayer.setTitle(LocaleController.getString("EncryptionKey", R.string.EncryptionKey)); - actionBarLayer.setTitleIcon(R.drawable.ic_lock_white, Utilities.dp(4)); + actionBarLayer.setTitleIcon(R.drawable.ic_lock_white, AndroidUtilities.dp(4)); actionBarLayer.setActionBarMenuOnItemClick(new ActionBarLayer.ActionBarMenuOnItemClick() { @Override diff --git a/TMessagesProj/src/main/java/org/telegram/ui/IntroActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/IntroActivity.java index 8c7d563a3..d8141fda8 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/IntroActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/IntroActivity.java @@ -24,7 +24,7 @@ import android.view.animation.AnimationUtils; import android.widget.ImageView; import android.widget.TextView; -import org.telegram.messenger.LocaleController; +import org.telegram.android.LocaleController; import org.telegram.messenger.R; import org.telegram.messenger.Utilities; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LanguageSelectActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/LanguageSelectActivity.java index 559613897..dc4e56ae0 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LanguageSelectActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LanguageSelectActivity.java @@ -20,8 +20,9 @@ import android.widget.EditText; import android.widget.ListView; import android.widget.TextView; +import org.telegram.android.AndroidUtilities; import org.telegram.messenger.FileLog; -import org.telegram.messenger.LocaleController; +import org.telegram.android.LocaleController; import org.telegram.messenger.R; import org.telegram.messenger.Utilities; import org.telegram.ui.Adapters.BaseFragmentAdapter; @@ -86,7 +87,7 @@ public class LanguageSelectActivity extends BaseFragment { if (text.length() != 0) { searchWas = true; if (listView != null) { - listView.setPadding(Utilities.dp(16), listView.getPaddingTop(), Utilities.dp(16), listView.getPaddingBottom()); + listView.setPadding(AndroidUtilities.dp(16), listView.getPaddingTop(), AndroidUtilities.dp(16), listView.getPaddingBottom()); listView.setAdapter(searchListViewAdapter); if(android.os.Build.VERSION.SDK_INT >= 11) { listView.setFastScrollAlwaysVisible(false); @@ -176,7 +177,7 @@ public class LanguageSelectActivity extends BaseFragment { @Override public void onScrollStateChanged(AbsListView absListView, int i) { if (i == SCROLL_STATE_TOUCH_SCROLL && searching && searchWas) { - Utilities.hideKeyboard(getParentActivity().getCurrentFocus()); + AndroidUtilities.hideKeyboard(getParentActivity().getCurrentFocus()); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java index 23de06c11..e0e7c221c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java @@ -8,38 +8,31 @@ package org.telegram.ui; -import android.app.NotificationManager; import android.content.ContentResolver; -import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; -import android.content.res.Configuration; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.os.Parcelable; import android.provider.ContactsContract; -import android.view.Surface; import android.view.View; -import android.view.WindowManager; -import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; +import org.telegram.android.AndroidUtilities; import org.telegram.PhoneFormat.PhoneFormat; import org.telegram.messenger.ConnectionsManager; import org.telegram.messenger.FileLog; -import org.telegram.messenger.LocaleController; -import org.telegram.messenger.MessagesController; +import org.telegram.android.LocaleController; +import org.telegram.android.MessagesController; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.TLRPC; import org.telegram.messenger.UserConfig; import org.telegram.messenger.Utilities; -import org.telegram.objects.MessageObject; import org.telegram.ui.Views.ActionBar.ActionBarActivity; import org.telegram.ui.Views.ActionBar.BaseFragment; -import org.telegram.ui.Views.NotificationView; import java.io.BufferedReader; import java.io.InputStream; @@ -49,7 +42,6 @@ import java.util.Map; public class LaunchActivity extends ActionBarActivity implements NotificationCenter.NotificationCenterDelegate, MessagesActivity.MessagesActivityDelegate { private boolean finished = false; - private NotificationView notificationView; private String videoPath = null; private String sendingText = null; private ArrayList photoPathsArray = null; @@ -86,11 +78,11 @@ public class LaunchActivity extends ActionBarActivity implements NotificationCen int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android"); if (resourceId > 0) { - Utilities.statusBarHeight = getResources().getDimensionPixelSize(resourceId); + AndroidUtilities.statusBarHeight = getResources().getDimensionPixelSize(resourceId); } NotificationCenter.getInstance().postNotificationName(702, this); - currentConnectionState = ConnectionsManager.getInstance().connectionState; + currentConnectionState = ConnectionsManager.getInstance().getConnectionState(); NotificationCenter.getInstance().addObserver(this, 1234); NotificationCenter.getInstance().addObserver(this, 658); @@ -504,14 +496,8 @@ public class LaunchActivity extends ActionBarActivity implements NotificationCen @Override protected void onPause() { super.onPause(); - ConnectionsManager.setAppPaused(true); - if (notificationView != null) { - notificationView.hide(false); - } - View focusView = getCurrentFocus(); - if (focusView instanceof EditText) { - focusView.clearFocus(); - } + ApplicationLoader.mainInterfacePaused = true; + ConnectionsManager.getInstance().setAppPaused(true, false); } @Override @@ -523,20 +509,12 @@ public class LaunchActivity extends ActionBarActivity implements NotificationCen @Override protected void onResume() { super.onResume(); - if (notificationView == null && getLayoutInflater() != null) { - notificationView = (NotificationView) getLayoutInflater().inflate(R.layout.notification_layout, null); - } Utilities.checkForCrashes(this); Utilities.checkForUpdates(this); - ConnectionsManager.setAppPaused(false); + ApplicationLoader.mainInterfacePaused = false; + ConnectionsManager.getInstance().setAppPaused(false, false); actionBar.setBackOverlayVisible(currentConnectionState != 0); - try { - NotificationManager mNotificationManager = (NotificationManager)this.getSystemService(Context.NOTIFICATION_SERVICE); - mNotificationManager.cancel(1); - MessagesController.getInstance().currentPushMessage = null; - } catch (Exception e) { - FileLog.e("tmessages", e); - } + MessagesController.getInstance().dismissNotification(); } @Override @@ -550,32 +528,12 @@ public class LaunchActivity extends ActionBarActivity implements NotificationCen NotificationCenter.getInstance().removeObserver(this, 701); NotificationCenter.getInstance().removeObserver(this, 702); NotificationCenter.getInstance().removeObserver(this, 703); - if (notificationView != null) { - notificationView.hide(false); - notificationView.destroy(); - notificationView = null; - } } @Override public void onConfigurationChanged(android.content.res.Configuration newConfig) { super.onConfigurationChanged(newConfig); - Utilities.checkDisplaySize(); - } - - @Override - public void needLayout() { - super.needLayout(); - if (notificationView != null) { - WindowManager manager = (WindowManager) getSystemService(WINDOW_SERVICE); - int rotation = manager.getDefaultDisplay().getRotation(); - - int height = Utilities.dp(48); - if (!Utilities.isTablet(this) && getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) { - height = Utilities.dp(40); - } - notificationView.applyOrientationPaddings(rotation == Surface.ROTATION_270 || rotation == Surface.ROTATION_90, height); - } + AndroidUtilities.checkDisplaySize(); } @Override @@ -614,11 +572,6 @@ public class LaunchActivity extends ActionBarActivity implements NotificationCen args2.putInt("enc_id", push_enc_id); presentFragment(new ChatActivity(args2), false, true); } - } else if (id == 701) { - if (notificationView != null) { - MessageObject message = (MessageObject)args[0]; - notificationView.show(message); - } } else if (id == 702) { if (args[0] != this) { onFinish(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LocationActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/LocationActivity.java index ddaa34639..c04854679 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LocationActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LocationActivity.java @@ -26,10 +26,10 @@ import com.google.android.gms.maps.model.Marker; import com.google.android.gms.maps.model.MarkerOptions; import org.telegram.messenger.FileLog; -import org.telegram.messenger.LocaleController; +import org.telegram.android.LocaleController; import org.telegram.messenger.TLRPC; import org.telegram.objects.MessageObject; -import org.telegram.messenger.MessagesController; +import org.telegram.android.MessagesController; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.Utilities; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LoginActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/LoginActivity.java index d19df2b59..aa2495a78 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LoginActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LoginActivity.java @@ -22,8 +22,9 @@ import android.widget.FrameLayout; import android.widget.ScrollView; import android.widget.TextView; +import org.telegram.android.AndroidUtilities; import org.telegram.messenger.FileLog; -import org.telegram.messenger.LocaleController; +import org.telegram.android.LocaleController; import org.telegram.messenger.R; import org.telegram.messenger.Utilities; import org.telegram.ui.Views.ActionBar.ActionBarLayer; @@ -265,7 +266,7 @@ public class LoginActivity extends BaseFragment implements SlideView.SlideViewDe newView.setParams(params); actionBarLayer.setTitle(newView.getHeaderName()); newView.onShow(); - newView.setX(back ? -Utilities.displaySize.x : Utilities.displaySize.x); + newView.setX(back ? -AndroidUtilities.displaySize.x : AndroidUtilities.displaySize.x); outView.animate().setInterpolator(new AccelerateDecelerateInterpolator()).setListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animator) { @@ -284,7 +285,7 @@ public class LoginActivity extends BaseFragment implements SlideView.SlideViewDe @Override public void onAnimationRepeat(Animator animator) { } - }).setDuration(300).translationX(back ? Utilities.displaySize.x : -Utilities.displaySize.x).start(); + }).setDuration(300).translationX(back ? AndroidUtilities.displaySize.x : -AndroidUtilities.displaySize.x).start(); newView.animate().setInterpolator(new AccelerateDecelerateInterpolator()).setListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animator) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LoginActivityPhoneView.java b/TMessagesProj/src/main/java/org/telegram/ui/LoginActivityPhoneView.java index 6d228ad8d..ea07252ea 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LoginActivityPhoneView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LoginActivityPhoneView.java @@ -21,9 +21,10 @@ import android.widget.AdapterView; import android.widget.EditText; import android.widget.TextView; +import org.telegram.android.AndroidUtilities; import org.telegram.PhoneFormat.PhoneFormat; import org.telegram.messenger.BuildVars; -import org.telegram.messenger.LocaleController; +import org.telegram.android.LocaleController; import org.telegram.messenger.TLObject; import org.telegram.messenger.TLRPC; import org.telegram.messenger.ConnectionsManager; @@ -250,10 +251,10 @@ public class LoginActivityPhoneView extends SlideView implements AdapterView.OnI } if (codeField.length() != 0) { - Utilities.showKeyboard(phoneField); + AndroidUtilities.showKeyboard(phoneField); phoneField.requestFocus(); } else { - Utilities.showKeyboard(codeField); + AndroidUtilities.showKeyboard(codeField); codeField.requestFocus(); } phoneField.setOnEditorActionListener(new TextView.OnEditorActionListener() { @@ -389,7 +390,7 @@ public class LoginActivityPhoneView extends SlideView implements AdapterView.OnI } }); } - }, null, true, RPCRequest.RPCRequestClassGeneric | RPCRequest.RPCRequestClassFailOnServerErrors | RPCRequest.RPCRequestClassWithoutLogin); + }, true, RPCRequest.RPCRequestClassGeneric | RPCRequest.RPCRequestClassFailOnServerErrors | RPCRequest.RPCRequestClassWithoutLogin); } @Override diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LoginActivityRegisterView.java b/TMessagesProj/src/main/java/org/telegram/ui/LoginActivityRegisterView.java index 7515aa74d..ec2dfd09c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LoginActivityRegisterView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LoginActivityRegisterView.java @@ -17,13 +17,13 @@ import android.view.inputmethod.EditorInfo; import android.widget.EditText; import android.widget.TextView; -import org.telegram.messenger.LocaleController; +import org.telegram.android.LocaleController; import org.telegram.messenger.TLObject; import org.telegram.messenger.TLRPC; import org.telegram.messenger.ConnectionsManager; -import org.telegram.messenger.ContactsController; -import org.telegram.messenger.MessagesController; -import org.telegram.messenger.MessagesStorage; +import org.telegram.android.ContactsController; +import org.telegram.android.MessagesController; +import org.telegram.android.MessagesStorage; import org.telegram.messenger.R; import org.telegram.messenger.RPCRequest; import org.telegram.messenger.UserConfig; @@ -184,7 +184,7 @@ public class LoginActivityRegisterView extends SlideView { } }); } - }, null, true, RPCRequest.RPCRequestClassGeneric | RPCRequest.RPCRequestClassWithoutLogin); + }, true, RPCRequest.RPCRequestClassGeneric | RPCRequest.RPCRequestClassWithoutLogin); } @Override diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LoginActivitySmsView.java b/TMessagesProj/src/main/java/org/telegram/ui/LoginActivitySmsView.java index 7c80b277b..f03db3574 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LoginActivitySmsView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LoginActivitySmsView.java @@ -18,15 +18,16 @@ import android.view.inputmethod.EditorInfo; import android.widget.EditText; import android.widget.TextView; +import org.telegram.android.AndroidUtilities; import org.telegram.PhoneFormat.PhoneFormat; -import org.telegram.messenger.LocaleController; +import org.telegram.android.LocaleController; import org.telegram.messenger.TLObject; import org.telegram.messenger.TLRPC; import org.telegram.messenger.ConnectionsManager; -import org.telegram.messenger.ContactsController; +import org.telegram.android.ContactsController; import org.telegram.messenger.FileLog; -import org.telegram.messenger.MessagesController; -import org.telegram.messenger.MessagesStorage; +import org.telegram.android.MessagesController; +import org.telegram.android.MessagesStorage; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.RPCRequest; @@ -110,7 +111,7 @@ public class LoginActivitySmsView extends SlideView implements NotificationCente return; } codeField.setText(""); - Utilities.setWaitingForSms(true); + AndroidUtilities.setWaitingForSms(true); NotificationCenter.getInstance().addObserver(this, 998); currentParams = params; waitingForSms = true; @@ -127,7 +128,7 @@ public class LoginActivitySmsView extends SlideView implements NotificationCente String number = PhoneFormat.getInstance().format(phone); confirmTextView.setText(Html.fromHtml(String.format(LocaleController.getString("SentSmsCode", R.string.SentSmsCode) + " %s", number))); - Utilities.showKeyboard(codeField); + AndroidUtilities.showKeyboard(codeField); codeField.requestFocus(); destroyTimer(); @@ -166,7 +167,7 @@ public class LoginActivitySmsView extends SlideView implements NotificationCente @Override public void run(TLObject response, TLRPC.TL_error error) { } - }, null, true, RPCRequest.RPCRequestClassGeneric | RPCRequest.RPCRequestClassFailOnServerErrors | RPCRequest.RPCRequestClassWithoutLogin); + }, true, RPCRequest.RPCRequestClassGeneric | RPCRequest.RPCRequestClassFailOnServerErrors | RPCRequest.RPCRequestClassWithoutLogin); } } }); @@ -194,7 +195,7 @@ public class LoginActivitySmsView extends SlideView implements NotificationCente } nextPressed = true; waitingForSms = false; - Utilities.setWaitingForSms(false); + AndroidUtilities.setWaitingForSms(false); NotificationCenter.getInstance().removeObserver(this, 998); final TLRPC.TL_auth_signIn req = new TLRPC.TL_auth_signIn(); req.phone_number = requestPhone; @@ -256,14 +257,14 @@ public class LoginActivitySmsView extends SlideView implements NotificationCente } }); } - }, null, true, RPCRequest.RPCRequestClassGeneric | RPCRequest.RPCRequestClassFailOnServerErrors | RPCRequest.RPCRequestClassWithoutLogin); + }, true, RPCRequest.RPCRequestClassGeneric | RPCRequest.RPCRequestClassFailOnServerErrors | RPCRequest.RPCRequestClassWithoutLogin); } @Override public void onBackPressed() { destroyTimer(); currentParams = null; - Utilities.setWaitingForSms(false); + AndroidUtilities.setWaitingForSms(false); NotificationCenter.getInstance().removeObserver(this, 998); waitingForSms = false; } @@ -271,7 +272,7 @@ public class LoginActivitySmsView extends SlideView implements NotificationCente @Override public void onDestroyActivity() { super.onDestroyActivity(); - Utilities.setWaitingForSms(false); + AndroidUtilities.setWaitingForSms(false); NotificationCenter.getInstance().removeObserver(this, 998); destroyTimer(); waitingForSms = false; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/MediaActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/MediaActivity.java index 087b7e60a..25513bb8e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/MediaActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/MediaActivity.java @@ -23,11 +23,11 @@ import android.widget.AdapterView; import android.widget.GridView; import android.widget.TextView; -import org.telegram.messenger.LocaleController; +import org.telegram.android.AndroidUtilities; +import org.telegram.android.LocaleController; import org.telegram.messenger.TLRPC; -import org.telegram.messenger.Utilities; import org.telegram.objects.MessageObject; -import org.telegram.messenger.MessagesController; +import org.telegram.android.MessagesController; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.objects.PhotoObject; @@ -284,7 +284,7 @@ public class MediaActivity extends BaseFragment implements NotificationCenter.No imageView.getLocationInWindow(coords); PhotoViewer.PlaceProviderObject object = new PhotoViewer.PlaceProviderObject(); object.viewX = coords[0]; - object.viewY = coords[1] - Utilities.statusBarHeight; + object.viewY = coords[1] - AndroidUtilities.statusBarHeight; object.parentView = listView; object.imageReceiver = imageView.imageReceiver; object.thumb = object.imageReceiver.getBitmap(); @@ -327,14 +327,14 @@ public class MediaActivity extends BaseFragment implements NotificationCenter.No if (rotation == Surface.ROTATION_270 || rotation == Surface.ROTATION_90) { listView.setNumColumns(6); - itemWidth = getParentActivity().getResources().getDisplayMetrics().widthPixels / 6 - Utilities.dp(2) * 5; + itemWidth = getParentActivity().getResources().getDisplayMetrics().widthPixels / 6 - AndroidUtilities.dp(2) * 5; listView.setColumnWidth(itemWidth); } else { listView.setNumColumns(4); - itemWidth = getParentActivity().getResources().getDisplayMetrics().widthPixels / 4 - Utilities.dp(2) * 3; + itemWidth = getParentActivity().getResources().getDisplayMetrics().widthPixels / 4 - AndroidUtilities.dp(2) * 3; listView.setColumnWidth(itemWidth); } - listView.setPadding(listView.getPaddingLeft(), Utilities.dp(4), listView.getPaddingRight(), listView.getPaddingBottom()); + listView.setPadding(listView.getPaddingLeft(), AndroidUtilities.dp(4), listView.getPaddingRight(), listView.getPaddingBottom()); listAdapter.notifyDataSetChanged(); if (listView != null) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/MessagesActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/MessagesActivity.java index 0913bfc83..1056bb7bf 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/MessagesActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/MessagesActivity.java @@ -21,13 +21,14 @@ import android.widget.EditText; import android.widget.ListView; import android.widget.TextView; -import org.telegram.messenger.LocaleController; +import org.telegram.android.AndroidUtilities; +import org.telegram.android.LocaleController; import org.telegram.messenger.TLObject; import org.telegram.messenger.TLRPC; -import org.telegram.messenger.ContactsController; +import org.telegram.android.ContactsController; import org.telegram.messenger.FileLog; -import org.telegram.messenger.MessagesController; -import org.telegram.messenger.MessagesStorage; +import org.telegram.android.MessagesController; +import org.telegram.android.MessagesStorage; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.UserConfig; @@ -347,7 +348,7 @@ public class MessagesActivity extends BaseFragment implements NotificationCenter @Override public void onScrollStateChanged(AbsListView absListView, int i) { if (i == SCROLL_STATE_TOUCH_SCROLL && searching && searchWas) { - Utilities.hideKeyboard(getParentActivity().getCurrentFocus()); + AndroidUtilities.hideKeyboard(getParentActivity().getCurrentFocus()); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PhotoCropActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PhotoCropActivity.java index 22e8395f4..a90b2e55f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PhotoCropActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PhotoCropActivity.java @@ -27,11 +27,11 @@ import android.widget.Button; import android.widget.FrameLayout; import android.widget.TextView; +import org.telegram.android.AndroidUtilities; import org.telegram.messenger.FileLoader; import org.telegram.messenger.FileLog; -import org.telegram.messenger.LocaleController; +import org.telegram.android.LocaleController; import org.telegram.messenger.R; -import org.telegram.messenger.Utilities; import org.telegram.ui.Views.ActionBar.BaseFragment; import java.io.File; @@ -72,7 +72,7 @@ public class PhotoCropActivity extends BaseFragment { private void init() { rectPaint = new Paint(); rectPaint.setColor(0xfffafafa); - rectPaint.setStrokeWidth(Utilities.dp(2)); + rectPaint.setStrokeWidth(AndroidUtilities.dp(2)); rectPaint.setStyle(Paint.Style.STROKE); circlePaint = new Paint(); circlePaint.setColor(0x7fffffff); @@ -85,7 +85,7 @@ public class PhotoCropActivity extends BaseFragment { public boolean onTouch(View view, MotionEvent motionEvent) { float x = motionEvent.getX(); float y = motionEvent.getY(); - int cornerSide = Utilities.dp(14); + int cornerSide = AndroidUtilities.dp(14); if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) { if (rectX - cornerSide < x && rectX + cornerSide > x && rectY - cornerSide < y && rectY + cornerSide > y) { draggingState = 1; @@ -270,7 +270,7 @@ public class PhotoCropActivity extends BaseFragment { canvas.drawRect(rectX, rectY, rectX + rectSize, rectY + rectSize, rectPaint); - int side = Utilities.dp(7); + int side = AndroidUtilities.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); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PhotoPickerActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PhotoPickerActivity.java index 6e17f0edc..ab4777b04 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PhotoPickerActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PhotoPickerActivity.java @@ -23,13 +23,13 @@ import android.widget.GridView; import android.widget.ImageView; import android.widget.TextView; -import org.telegram.messenger.LocaleController; -import org.telegram.messenger.MediaController; -import org.telegram.messenger.MessagesController; +import org.telegram.android.AndroidUtilities; +import org.telegram.android.LocaleController; +import org.telegram.android.MediaController; +import org.telegram.android.MessagesController; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.TLRPC; -import org.telegram.messenger.Utilities; import org.telegram.objects.MessageObject; import org.telegram.ui.Adapters.BaseFragmentAdapter; import org.telegram.ui.Views.ActionBar.ActionBarLayer; @@ -252,7 +252,7 @@ public class PhotoPickerActivity extends BaseFragment implements NotificationCen imageView.getLocationInWindow(coords); PhotoViewer.PlaceProviderObject object = new PhotoViewer.PlaceProviderObject(); object.viewX = coords[0]; - object.viewY = coords[1] - Utilities.statusBarHeight; + object.viewY = coords[1] - AndroidUtilities.statusBarHeight; object.parentView = listView; object.imageReceiver = imageView.imageReceiver; object.thumb = object.imageReceiver.getBitmap(); @@ -405,7 +405,7 @@ public class PhotoPickerActivity extends BaseFragment implements NotificationCen } } listView.setNumColumns(columnsCount); - itemWidth = (getParentActivity().getResources().getDisplayMetrics().widthPixels - ((columnsCount + 1) * Utilities.dp(4))) / columnsCount; + itemWidth = (getParentActivity().getResources().getDisplayMetrics().widthPixels - ((columnsCount + 1) * AndroidUtilities.dp(4))) / columnsCount; listView.setColumnWidth(itemWidth); listAdapter.notifyDataSetChanged(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java index a4168a8c8..668bd25d3 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java @@ -45,12 +45,13 @@ import android.widget.ProgressBar; import android.widget.Scroller; import android.widget.TextView; +import org.telegram.android.AndroidUtilities; import org.telegram.messenger.ConnectionsManager; import org.telegram.messenger.FileLoader; import org.telegram.messenger.FileLog; -import org.telegram.messenger.LocaleController; -import org.telegram.messenger.MediaController; -import org.telegram.messenger.MessagesController; +import org.telegram.android.LocaleController; +import org.telegram.android.MediaController; +import org.telegram.android.MessagesController; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.TLRPC; @@ -102,6 +103,8 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat private boolean overlayViewVisible = true; private int animationInProgress = 0; + private long transitionAnimationStartTime = 0; + private Runnable animationEndRunnable = null; private PlaceProviderObject showAfterAnimation; private PlaceProviderObject hideAfterAnimation; private boolean disableShowCheck = false; @@ -175,7 +178,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat private final static int gallery_menu_showall = 2; private final static int gallery_menu_send = 3; - private final static int PAGE_SPACING = Utilities.dp(30); + private final static int PAGE_SPACING = AndroidUtilities.dp(30); private static class OverlayView extends FrameLayout { @@ -186,7 +189,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat actionButton = new TextView(context); actionButton.setBackgroundResource(R.drawable.system_black); - actionButton.setPadding(Utilities.dp(8), Utilities.dp(2), Utilities.dp(8), Utilities.dp(2)); + actionButton.setPadding(AndroidUtilities.dp(8), AndroidUtilities.dp(2), AndroidUtilities.dp(8), AndroidUtilities.dp(2)); actionButton.setTextColor(0xffffffff); actionButton.setTextSize(26); actionButton.setGravity(Gravity.CENTER); @@ -298,7 +301,17 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat if (currentFileName != null && currentFileName.equals(location)) { Float progress = (Float)args[1]; progressBar.setVisibility(View.VISIBLE); - progressBar.setProgress((int)(progress * 100)); + if (android.os.Build.VERSION.SDK_INT >= 11) { + progressBar.setProgress((int) (progress * 100)); + AnimatorSet animatorSet = new AnimatorSet(); + animatorSet.playTogether( + ObjectAnimator.ofInt(progressBar, "progress", (int) (progress * 100)) + ); + animatorSet.setDuration(400); + animatorSet.start(); + } else { + progressBar.setProgress((int) (progress * 100)); + } } } else if (id == MessagesController.userPhotosLoaded) { int guid = (Integer)args[4]; @@ -530,7 +543,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat @Override public boolean canOpenMenu() { if (currentFileName != null) { - File f = new File(Utilities.getCacheDir(), currentFileName); + File f = new File(AndroidUtilities.getCacheDir(), currentFileName); if (f.exists()) { return true; } @@ -548,7 +561,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat containerView.addView(bottomLayout); layoutParams = (FrameLayout.LayoutParams)bottomLayout.getLayoutParams(); layoutParams.width = FrameLayout.LayoutParams.MATCH_PARENT; - layoutParams.height = Utilities.dp(48); + layoutParams.height = AndroidUtilities.dp(48); layoutParams.gravity = Gravity.BOTTOM | Gravity.LEFT; bottomLayout.setLayoutParams(layoutParams); bottomLayout.setBackgroundColor(0x7F000000); @@ -559,7 +572,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat shareButton.setBackgroundResource(R.drawable.bar_selector_white); bottomLayout.addView(shareButton); layoutParams = (FrameLayout.LayoutParams) shareButton.getLayoutParams(); - layoutParams.width = Utilities.dp(50); + layoutParams.width = AndroidUtilities.dp(50); layoutParams.height = FrameLayout.LayoutParams.MATCH_PARENT; shareButton.setLayoutParams(layoutParams); shareButton.setOnClickListener(new View.OnClickListener() { @@ -573,7 +586,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat if (fileName == null) { return; } - File f = new File(Utilities.getCacheDir(), fileName); + File f = new File(AndroidUtilities.getCacheDir(), fileName); if (f.exists()) { Intent intent = new Intent(Intent.ACTION_SEND); if (fileName.endsWith("mp4")) { @@ -596,7 +609,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat deleteButton.setBackgroundResource(R.drawable.bar_selector_white); bottomLayout.addView(deleteButton); layoutParams = (FrameLayout.LayoutParams) deleteButton.getLayoutParams(); - layoutParams.width = Utilities.dp(50); + layoutParams.width = AndroidUtilities.dp(50); layoutParams.height = FrameLayout.LayoutParams.MATCH_PARENT; layoutParams.gravity = Gravity.RIGHT; deleteButton.setLayoutParams(layoutParams); @@ -628,9 +641,9 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat layoutParams.width = FrameLayout.LayoutParams.MATCH_PARENT; layoutParams.height = FrameLayout.LayoutParams.WRAP_CONTENT; layoutParams.gravity = Gravity.TOP; - layoutParams.leftMargin = Utilities.dp(60); - layoutParams.rightMargin = Utilities.dp(60); - layoutParams.topMargin = Utilities.dp(2); + layoutParams.leftMargin = AndroidUtilities.dp(60); + layoutParams.rightMargin = AndroidUtilities.dp(60); + layoutParams.topMargin = AndroidUtilities.dp(2); nameTextView.setLayoutParams(layoutParams); dateTextView = new TextView(containerView.getContext()); @@ -645,9 +658,9 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat layoutParams.width = FrameLayout.LayoutParams.MATCH_PARENT; layoutParams.height = FrameLayout.LayoutParams.WRAP_CONTENT; layoutParams.gravity = Gravity.TOP; - layoutParams.leftMargin = Utilities.dp(60); - layoutParams.rightMargin = Utilities.dp(60); - layoutParams.topMargin = Utilities.dp(26); + layoutParams.leftMargin = AndroidUtilities.dp(60); + layoutParams.rightMargin = AndroidUtilities.dp(60); + layoutParams.topMargin = AndroidUtilities.dp(26); dateTextView.setLayoutParams(layoutParams); pickerView = parentActivity.getLayoutInflater().inflate(R.layout.photo_picker_bottom_layout, null); @@ -675,7 +688,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat layoutParams = (FrameLayout.LayoutParams)pickerView.getLayoutParams(); layoutParams.width = FrameLayout.LayoutParams.MATCH_PARENT; - layoutParams.height = Utilities.dp(48); + layoutParams.height = AndroidUtilities.dp(48); layoutParams.gravity = Gravity.BOTTOM; pickerView.setLayoutParams(layoutParams); @@ -691,11 +704,11 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat containerView.addView(progressBar); layoutParams = (FrameLayout.LayoutParams)progressBar.getLayoutParams(); layoutParams.width = FrameLayout.LayoutParams.MATCH_PARENT; - layoutParams.height = Utilities.dp(3); + layoutParams.height = AndroidUtilities.dp(3); layoutParams.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL; - layoutParams.leftMargin = Utilities.dp(6); - layoutParams.rightMargin = Utilities.dp(6); - layoutParams.bottomMargin = Utilities.dp(48); + layoutParams.leftMargin = AndroidUtilities.dp(6); + layoutParams.rightMargin = AndroidUtilities.dp(6); + layoutParams.bottomMargin = AndroidUtilities.dp(48); progressBar.setLayoutParams(layoutParams); gestureDetector = new GestureDetector(containerView.getContext(), this); @@ -715,16 +728,16 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat checkImageView.setScaleType(ImageView.ScaleType.CENTER); checkImageView.setImageResource(R.drawable.selectphoto_large); layoutParams = (FrameLayout.LayoutParams)checkImageView.getLayoutParams(); - layoutParams.width = Utilities.dp(46); - layoutParams.height = Utilities.dp(46); + layoutParams.width = AndroidUtilities.dp(46); + layoutParams.height = AndroidUtilities.dp(46); layoutParams.gravity = Gravity.RIGHT; - layoutParams.rightMargin = Utilities.dp(10); + layoutParams.rightMargin = AndroidUtilities.dp(10); WindowManager manager = (WindowManager)ApplicationLoader.applicationContext.getSystemService(Activity.WINDOW_SERVICE); int rotation = manager.getDefaultDisplay().getRotation(); if (rotation == Surface.ROTATION_270 || rotation == Surface.ROTATION_90) { - layoutParams.topMargin = Utilities.dp(48); + layoutParams.topMargin = AndroidUtilities.dp(48); } else { - layoutParams.topMargin = Utilities.dp(58); + layoutParams.topMargin = AndroidUtilities.dp(58); } checkImageView.setLayoutParams(layoutParams); checkImageView.setOnClickListener(new View.OnClickListener() { @@ -988,7 +1001,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat load = true; } } else { - File cacheFile = new File(Utilities.getCacheDir(), currentFileName); + File cacheFile = new File(AndroidUtilities.getCacheDir(), currentFileName); if (cacheFile.exists()) { currentOverlay.actionButton.setText(LocaleController.getString("ViewVideo", R.string.ViewVideo)); } else { @@ -996,10 +1009,13 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } } if (load) { - Float progress = FileLoader.getInstance().fileProgresses.get(currentFileName); if (FileLoader.getInstance().isLoadingFile(currentFileName)) { + Float progress = FileLoader.getInstance().fileProgresses.get(currentFileName); currentOverlay.actionButton.setText(LocaleController.getString("CancelDownload", R.string.CancelDownload)); progressBar.setVisibility(View.VISIBLE); + if (progress != null) { + progressBar.setProgress((int)(progress * 100)); + } } else { currentOverlay.actionButton.setText(String.format("%s %s", LocaleController.getString("DOWNLOAD", R.string.DOWNLOAD), Utilities.formatFileSize(currentMessageObject.messageOwner.media.video.size))); progressBar.setVisibility(View.GONE); @@ -1226,7 +1242,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } if (currentFileName != null) { - File f = new File(Utilities.getCacheDir(), currentFileName); + File f = new File(AndroidUtilities.getCacheDir(), currentFileName); if (f.exists()) { progressBar.setVisibility(View.GONE); } else { @@ -1260,7 +1276,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat if (currentThumb != null && imageReceiver == centerImage) { placeHolder = currentThumb; } - int size = (int)(800 / Utilities.density); + int size = (int)(800 / AndroidUtilities.density); imageReceiver.setImage(photoEntry.path, String.format(Locale.US, "%d_%d", size, size), placeHolder != null ? new BitmapDrawable(null, placeHolder) : null); } else { imageReceiver.setImageBitmap((Bitmap) null); @@ -1335,8 +1351,21 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat openPhoto(null, null, null, photos, index, provider); } + private boolean checkAnimation() { + if (animationInProgress != 0) { + if (Math.abs(transitionAnimationStartTime - System.currentTimeMillis()) >= 500) { + if (animationEndRunnable != null) { + animationEndRunnable.run(); + animationEndRunnable = null; + } + animationInProgress = 0; + } + } + return animationInProgress != 0; + } + public void openPhoto(final MessageObject messageObject, final TLRPC.FileLocation fileLocation, final ArrayList messages, final ArrayList photos, final int index, final PhotoViewerProvider provider) { - if (parentActivity == null || isVisible || provider == null || animationInProgress != 0 || messageObject == null && fileLocation == null && messages == null && photos == null) { + if (parentActivity == null || isVisible || provider == null || checkAnimation() || messageObject == null && fileLocation == null && messages == null && photos == null) { return; } final PlaceProviderObject object = provider.getPlaceForPhoto(messageObject, fileLocation, index); @@ -1369,7 +1398,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat overlayViewVisible = true; if(android.os.Build.VERSION.SDK_INT >= 11) { - Utilities.lockOrientation(parentActivity); + AndroidUtilities.lockOrientation(parentActivity); animatingImageView.setVisibility(View.VISIBLE); animatingImageView.setImageBitmap(object.thumb); @@ -1391,23 +1420,23 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat public boolean onPreDraw() { containerView.getViewTreeObserver().removeOnPreDrawListener(this); - float scaleX = (float) Utilities.displaySize.x / layoutParams.width; - float scaleY = (float) (Utilities.displaySize.y - Utilities.statusBarHeight) / layoutParams.height; + float scaleX = (float) AndroidUtilities.displaySize.x / layoutParams.width; + float scaleY = (float) (AndroidUtilities.displaySize.y - AndroidUtilities.statusBarHeight) / layoutParams.height; float scale = scaleX > scaleY ? scaleY : scaleX; float width = layoutParams.width * scale; float height = layoutParams.height * scale; - float xPos = (Utilities.displaySize.x - width) / 2.0f; - float yPos = (Utilities.displaySize.y - Utilities.statusBarHeight - height) / 2.0f; + float xPos = (AndroidUtilities.displaySize.x - width) / 2.0f; + float yPos = (AndroidUtilities.displaySize.y - AndroidUtilities.statusBarHeight - height) / 2.0f; int clipHorizontal = Math.abs(object.imageReceiver.drawRegion.left - object.imageReceiver.imageX); int clipVertical = Math.abs(object.imageReceiver.drawRegion.top - object.imageReceiver.imageY); int coords2[] = new int[2]; object.parentView.getLocationInWindow(coords2); - int clipTop = coords2[1] - Utilities.statusBarHeight - (object.viewY + object.imageReceiver.drawRegion.top); + int clipTop = coords2[1] - AndroidUtilities.statusBarHeight - (object.viewY + object.imageReceiver.drawRegion.top); if (clipTop < 0) { clipTop = 0; } - int clipBottom = (object.viewY + object.imageReceiver.drawRegion.top + layoutParams.height) - (coords2[1] + object.parentView.getHeight() - Utilities.statusBarHeight); + int clipBottom = (object.viewY + object.imageReceiver.drawRegion.top + layoutParams.height) - (coords2[1] + object.parentView.getHeight() - AndroidUtilities.statusBarHeight); if (clipBottom < 0) { clipBottom = 0; } @@ -1428,14 +1457,14 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat ObjectAnimator.ofFloat(currentOverlay, "alpha", 1.0f) ); - animatorSet.setDuration(250); - animatorSet.addListener(new AnimatorListenerAdapter() { + animationEndRunnable = new Runnable() { @Override - public void onAnimationEnd(Animator animation) { + public void run() { animationInProgress = 0; + transitionAnimationStartTime = 0; containerView.invalidate(); animatingImageView.setVisibility(View.GONE); - Utilities.unlockOrientation(parentActivity); + AndroidUtilities.unlockOrientation(parentActivity); if (showAfterAnimation != null) { showAfterAnimation.imageReceiver.setVisible(true, true); } @@ -1443,7 +1472,24 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat hideAfterAnimation.imageReceiver.setVisible(false, true); } } + }; + + animatorSet.setDuration(250); + animatorSet.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + if (animationEndRunnable != null) { + animationEndRunnable.run(); + animationEndRunnable = null; + } + } + + @Override + public void onAnimationCancel(Animator animation) { + onAnimationEnd(animation); + } }); + transitionAnimationStartTime = System.currentTimeMillis(); animatorSet.start(); animatingImageView.setOnDrawListener(new ClippingImageView.onDrawListener() { @@ -1461,6 +1507,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat }); } else { animationInProgress = 0; + transitionAnimationStartTime = 0; containerView.invalidate(); AnimationSet animationSet = new AnimationSet(true); AlphaAnimation animation = new AlphaAnimation(0.0f, 1.0f); @@ -1478,7 +1525,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } public void closePhoto(boolean animated) { - if (parentActivity == null || !isVisible || animationInProgress != 0) { + if (parentActivity == null || !isVisible || checkAnimation()) { return; } @@ -1502,7 +1549,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat final PlaceProviderObject object = placeProvider.getPlaceForPhoto(currentMessageObject, currentFileLocation, currentIndex); if(android.os.Build.VERSION.SDK_INT >= 11 && animated) { - Utilities.lockOrientation(parentActivity); + AndroidUtilities.lockOrientation(parentActivity); animationInProgress = 1; animatingImageView.setVisibility(View.VISIBLE); @@ -1522,13 +1569,13 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } animatingImageView.setLayoutParams(layoutParams); - float scaleX = (float) Utilities.displaySize.x / layoutParams.width; - float scaleY = (float) (Utilities.displaySize.y - Utilities.statusBarHeight) / layoutParams.height; + float scaleX = (float) AndroidUtilities.displaySize.x / layoutParams.width; + float scaleY = (float) (AndroidUtilities.displaySize.y - AndroidUtilities.statusBarHeight) / layoutParams.height; float scale2 = scaleX > scaleY ? scaleY : scaleX; float width = layoutParams.width * scale * scale2; float height = layoutParams.height * scale * scale2; - float xPos = (Utilities.displaySize.x - width) / 2.0f; - float yPos = (Utilities.displaySize.y - Utilities.statusBarHeight - height) / 2.0f; + float xPos = (AndroidUtilities.displaySize.x - width) / 2.0f; + float yPos = (AndroidUtilities.displaySize.y - AndroidUtilities.statusBarHeight - height) / 2.0f; animatingImageView.setTranslationX(xPos + translationX); animatingImageView.setTranslationY(yPos + translationY); animatingImageView.setScaleX(scale * scale2); @@ -1543,11 +1590,11 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat int coords2[] = new int[2]; object.parentView.getLocationInWindow(coords2); - int clipTop = coords2[1] - Utilities.statusBarHeight - (object.viewY + object.imageReceiver.drawRegion.top); + int clipTop = coords2[1] - AndroidUtilities.statusBarHeight - (object.viewY + object.imageReceiver.drawRegion.top); if (clipTop < 0) { clipTop = 0; } - int clipBottom = (object.viewY + object.imageReceiver.drawRegion.top + (object.imageReceiver.drawRegion.bottom - object.imageReceiver.drawRegion.top)) - (coords2[1] + object.parentView.getHeight() - Utilities.statusBarHeight); + int clipBottom = (object.viewY + object.imageReceiver.drawRegion.top + (object.imageReceiver.drawRegion.bottom - object.imageReceiver.drawRegion.top)) - (coords2[1] + object.parentView.getHeight() - AndroidUtilities.statusBarHeight); if (clipBottom < 0) { clipBottom = 0; } @@ -1570,20 +1617,36 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat animatorSet.playTogether( ObjectAnimator.ofInt(backgroundDrawable, "alpha", 0), ObjectAnimator.ofFloat(animatingImageView, "alpha", 0.0f), - ObjectAnimator.ofFloat(animatingImageView, "translationY", translationY >= 0 ? Utilities.displaySize.y : -Utilities.displaySize.y), + ObjectAnimator.ofFloat(animatingImageView, "translationY", translationY >= 0 ? AndroidUtilities.displaySize.y : -AndroidUtilities.displaySize.y), ObjectAnimator.ofFloat(containerView, "alpha", 0.0f) ); } + animationEndRunnable = new Runnable() { + @Override + public void run() { + AndroidUtilities.unlockOrientation(parentActivity); + animationInProgress = 0; + onPhotoClosed(object); + } + }; + animatorSet.setDuration(250); animatorSet.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { - Utilities.unlockOrientation(parentActivity); - animationInProgress = 0; - onPhotoClosed(object); + if (animationEndRunnable != null) { + animationEndRunnable.run(); + animationEndRunnable = null; + } + } + + @Override + public void onAnimationCancel(Animator animation) { + onAnimationEnd(animation); } }); + transitionAnimationStartTime = System.currentTimeMillis(); animatorSet.start(); } else { AnimationSet animationSet = new AnimationSet(true); @@ -1597,6 +1660,16 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat animationSet.addAnimation(scaleAnimation); animationSet.setDuration(150); animationInProgress = 2; + animationEndRunnable = new Runnable() { + @Override + public void run() { + if (animationListener != null) { + animationInProgress = 0; + onPhotoClosed(object); + animationListener = null; + } + } + }; animationSet.setAnimationListener(animationListener = new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { @@ -1605,10 +1678,9 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat @Override public void onAnimationEnd(Animation animation) { - if (animationListener != null) { - animationInProgress = 0; - onPhotoClosed(object); - animationListener = null; + if (animationEndRunnable != null) { + animationEndRunnable.run(); + animationEndRunnable = null; } } @@ -1617,6 +1689,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } }); + transitionAnimationStartTime = System.currentTimeMillis(); containerView.startAnimation(animationSet); } } @@ -1678,7 +1751,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat private boolean onTouchEvent(MotionEvent ev) { if (animationInProgress != 0 || animationStartTime != 0) { if (animationStartTime == 0) { - Utilities.unlockOrientation(parentActivity); + AndroidUtilities.unlockOrientation(parentActivity); } return false; } @@ -1713,7 +1786,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat dragY = moveStartY = ev.getY(); draggingDown = false; canDragDown = true; - Utilities.lockOrientation(parentActivity); + AndroidUtilities.lockOrientation(parentActivity); if (velocityTracker != null) { velocityTracker.clear(); } @@ -1732,7 +1805,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } float dx = Math.abs(ev.getX() - moveStartX); float dy = Math.abs(ev.getY() - dragY); - if (canDragDown && !draggingDown && scale == 1 && dy >= Utilities.dp(30) && dy / 2 > dx) { + if (canDragDown && !draggingDown && scale == 1 && dy >= AndroidUtilities.dp(30) && dy / 2 > dx) { draggingDown = true; moving = false; dragY = ev.getY(); @@ -1747,7 +1820,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } else if (!invalidCoords && animationStartTime == 0) { float moveDx = moveStartX - ev.getX(); float moveDy = moveStartY - ev.getY(); - if (moving || scale == 1 && Math.abs(moveDy) + Utilities.dp(12) < Math.abs(moveDx) || scale != 1) { + if (moving || scale == 1 && Math.abs(moveDy) + AndroidUtilities.dp(12) < Math.abs(moveDx) || scale != 1) { if (!moving) { moveDx = 0; moveDy = 0; @@ -1834,11 +1907,11 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat velocity = velocityTracker.getXVelocity(); } - if((translationX < minX - containerView.getWidth() / 3 || velocity < -Utilities.dp(650)) && rightImage.hasImage()){ + if((translationX < minX - containerView.getWidth() / 3 || velocity < -AndroidUtilities.dp(650)) && rightImage.hasImage()){ goToNext(); return true; } - if((translationX > maxX + containerView.getWidth() / 3 || velocity > Utilities.dp(650)) && leftImage.hasImage()){ + if((translationX > maxX + containerView.getWidth() / 3 || velocity > AndroidUtilities.dp(650)) && leftImage.hasImage()){ goToPrev(); return true; } @@ -1855,7 +1928,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } animateTo(scale, moveToX, moveToY); } else { - Utilities.unlockOrientation(parentActivity); + AndroidUtilities.unlockOrientation(parentActivity); } } return false; @@ -1905,7 +1978,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat toggleOverlayView(true); } if (scale == newScale && translationX == newTx && translationY == newTy) { - Utilities.unlockOrientation(parentActivity); + AndroidUtilities.unlockOrientation(parentActivity); return; } zoomAnimation = isZoom; @@ -1915,7 +1988,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat animationStartTime = System.currentTimeMillis(); animationDuration = 250; containerView.postInvalidate(); - Utilities.lockOrientation(parentActivity); + AndroidUtilities.lockOrientation(parentActivity); } private void onDraw(Canvas canvas) { @@ -1962,7 +2035,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat scale = animateToScale; animationStartTime = 0; updateMinMax(scale); - Utilities.unlockOrientation(parentActivity); + AndroidUtilities.unlockOrientation(parentActivity); zoomAnimation = false; } if (!scroller.isFinished()) { @@ -2023,10 +2096,10 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat if (scale >= 1.0f) { ImageReceiver sideImage = null; float k = 1; - if (currentTranslationX > maxX + Utilities.dp(20)) { + if (currentTranslationX > maxX + AndroidUtilities.dp(20)) { k = -1; sideImage = leftImage; - } else if (currentTranslationX < minX - Utilities.dp(20)) { + } else if (currentTranslationX < minX - AndroidUtilities.dp(20)) { sideImage = rightImage; } @@ -2078,9 +2151,9 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat WindowManager manager = (WindowManager)ApplicationLoader.applicationContext.getSystemService(Activity.WINDOW_SERVICE); int rotation = manager.getDefaultDisplay().getRotation(); if (rotation == Surface.ROTATION_270 || rotation == Surface.ROTATION_90) { - layoutParams.topMargin = Utilities.dp(48); + layoutParams.topMargin = AndroidUtilities.dp(48); } else { - layoutParams.topMargin = Utilities.dp(58); + layoutParams.topMargin = AndroidUtilities.dp(58); } checkImageView.setLayoutParams(layoutParams); return false; @@ -2105,7 +2178,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat loadFile = true; } } else { - File cacheFile = new File(Utilities.getCacheDir(), currentFileName); + File cacheFile = new File(AndroidUtilities.getCacheDir(), currentFileName); if (cacheFile.exists()) { Intent intent = new Intent(Intent.ACTION_VIEW); intent.setDataAndType(Uri.fromFile(cacheFile), "video/mp4"); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PopupNotificationActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PopupNotificationActivity.java new file mode 100644 index 000000000..941870de5 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/PopupNotificationActivity.java @@ -0,0 +1,418 @@ +/* + * This is the source code of Telegram for Android v. 1.4.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-2014. + */ + +package org.telegram.ui; + +import android.app.Activity; +import android.app.KeyguardManager; +import android.content.Context; +import android.content.Intent; +import android.graphics.drawable.AnimationDrawable; +import android.os.Bundle; +import android.os.PowerManager; +import android.util.TypedValue; +import android.view.View; +import android.view.ViewGroup; +import android.view.WindowManager; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import org.telegram.android.AndroidUtilities; +import org.telegram.android.ContactsController; +import org.telegram.android.LocaleController; +import org.telegram.android.MessagesController; +import org.telegram.PhoneFormat.PhoneFormat; +import org.telegram.messenger.ConnectionsManager; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.R; +import org.telegram.messenger.TLRPC; +import org.telegram.messenger.Utilities; +import org.telegram.objects.MessageObject; +import org.telegram.ui.Views.ActionBar.ActionBar; +import org.telegram.ui.Views.ActionBar.ActionBarLayer; +import org.telegram.ui.Views.ActionBar.ActionBarMenu; +import org.telegram.ui.Views.BackupImageView; +import org.telegram.ui.Views.ChatActivityEnterView; + +public class PopupNotificationActivity extends Activity implements NotificationCenter.NotificationCenterDelegate { + + private ActionBarLayer actionBarLayer; + private ChatActivityEnterView chatActivityEnterView; + private BackupImageView avatarImageView; + private TextView messageText; + private TextView countText; + private View textScroll; + + private int classGuid; + private TLRPC.User currentUser; + private TLRPC.Chat currentChat; + private boolean finished = false; + private CharSequence lastPrintString; + private MessageObject currentMessageObject = null; + private int currentMessageNum = 0; + private PowerManager.WakeLock wakeLock = null; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + classGuid = ConnectionsManager.getInstance().generateClassGuid(); + NotificationCenter.getInstance().addObserver(this, 1234); + NotificationCenter.getInstance().addObserver(this, MessagesController.pushMessagesUpdated); + NotificationCenter.getInstance().addObserver(this, MessagesController.updateInterfaces); + + chatActivityEnterView = new ChatActivityEnterView(); + chatActivityEnterView.setDelegate(new ChatActivityEnterView.ChatActivityEnterViewDelegate() { + @Override + public void onMessageSend() { + MessagesController.getInstance().pushMessages.remove(0); + currentMessageObject = null; + getNewMessage(); + //MessagesController.getInstance().markDialogAsRead(dialog_id, messages.get(0).messageOwner.id, minMessageId, 0, maxDate, wasUnread); + } + + @Override + public void needSendTyping() { + if (currentMessageObject != null) { + MessagesController.getInstance().sendTyping(currentMessageObject.getDialogId(), classGuid); + } + } + }); + + setContentView(R.layout.popup_notification_layout); + RelativeLayout popupContainer = (RelativeLayout) findViewById(R.id.popup_container); + messageText = (TextView)findViewById(R.id.message_text); + View messageContainer = findViewById(R.id.text_container); + messageContainer.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + openCurrentMessage(); + } + }); + + ActionBar actionBar = new ActionBar(this); + popupContainer.addView(actionBar); + ViewGroup.LayoutParams layoutParams = actionBar.getLayoutParams(); + layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT; + actionBar.setLayoutParams(layoutParams); + + actionBarLayer = actionBar.createLayer(); + actionBarLayer.setDisplayHomeAsUpEnabled(true, R.drawable.ic_ab_back); + actionBarLayer.setBackgroundResource(R.color.header); + actionBarLayer.setItemsBackground(R.drawable.bar_selector); + actionBar.setCurrentActionBarLayer(actionBarLayer); + + ActionBarMenu menu = actionBarLayer.createMenu(); + View view = menu.addItemResource(2, R.layout.popup_count_layout); + countText = (TextView) view.findViewById(R.id.count_text); + + view = menu.addItemResource(1, R.layout.chat_header_layout); + avatarImageView = (BackupImageView)view.findViewById(R.id.chat_avatar_image); + avatarImageView.processDetach = false; + + actionBarLayer.setActionBarMenuOnItemClick(new ActionBarLayer.ActionBarMenuOnItemClick() { + @Override + public void onItemClick(int id) { + if (id == -1) { + finish(); + } else if (id == 1) { + openCurrentMessage(); + } else if (id == 2) { + if (MessagesController.getInstance().pushMessages.size() > 1) { + if (currentMessageNum < MessagesController.getInstance().pushMessages.size() - 1) { + currentMessageNum++; + } else { + currentMessageNum = 0; + } + currentMessageObject = MessagesController.getInstance().pushMessages.get(currentMessageNum); + updateInterfaceForCurrentMessage(); + countText.setText(String.format("%d/%d", currentMessageNum + 1, MessagesController.getInstance().pushMessages.size())); + } + } + } + }); + + chatActivityEnterView.setContainerView(this, findViewById(R.id.chat_layout)); + + PowerManager pm = (PowerManager)ApplicationLoader.applicationContext.getSystemService(Context.POWER_SERVICE); + wakeLock = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, "screen"); + + handleIntent(getIntent()); + } + + @Override + protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + handleIntent(intent); + } + + public void handleIntent(Intent intent) { + KeyguardManager km = (KeyguardManager) getSystemService(KEYGUARD_SERVICE); + if (km.inKeyguardRestrictedInputMode() || !ApplicationLoader.isScreenOn) { + getWindow().addFlags( + WindowManager.LayoutParams.FLAG_DIM_BEHIND | + WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED | + WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON | + WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN); + } else { + getWindow().addFlags( + WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED | + WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON | + WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN); + getWindow().clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND); + } + + if (currentMessageObject == null) { + currentMessageNum = 0; + getNewMessage(); + } + wakeLock.acquire(7000); + } + + private void getNewMessage() { + if (MessagesController.getInstance().pushMessages.isEmpty()) { + finish(); + return; + } + + boolean found = false; + if ((currentMessageNum != 0 || chatActivityEnterView.hasText()) && currentMessageObject != null) { + for (int a = 0; a < MessagesController.getInstance().pushMessages.size(); a++) { + if (MessagesController.getInstance().pushMessages.get(a).messageOwner.id == currentMessageObject.messageOwner.id) { + currentMessageNum = a; + found = true; + break; + } + } + } + if (!found) { + currentMessageObject = MessagesController.getInstance().pushMessages.get(0); + updateInterfaceForCurrentMessage(); + } + countText.setText(String.format("%d/%d", currentMessageNum + 1, MessagesController.getInstance().pushMessages.size())); + } + + private void openCurrentMessage() { + if (currentMessageObject == null) { + return; + } + Intent intent = new Intent(ApplicationLoader.applicationContext, LaunchActivity.class); + long dialog_id = currentMessageObject.getDialogId(); + if ((int)dialog_id != 0) { + int lower_id = (int)dialog_id; + if (lower_id < 0) { + intent.putExtra("chatId", -lower_id); + } else { + intent.putExtra("userId", lower_id); + } + } else { + intent.putExtra("encId", (int)(dialog_id >> 32)); + } + intent.setAction("com.tmessages.openchat" + Math.random() + Integer.MAX_VALUE); + intent.setFlags(0x00008000); + startActivity(intent); + } + + private void updateInterfaceForCurrentMessage() { + if (actionBarLayer == null) { + return; + } + currentChat = null; + currentUser = null; + long dialog_id = currentMessageObject.getDialogId(); + chatActivityEnterView.setDialogId(dialog_id); + if ((int)dialog_id != 0) { + int lower_id = (int)dialog_id; + if (lower_id > 0) { + currentUser = MessagesController.getInstance().users.get(lower_id); + } else { + currentChat = MessagesController.getInstance().chats.get(-lower_id); + currentUser = MessagesController.getInstance().users.get(currentMessageObject.messageOwner.from_id); + } + } else { + TLRPC.EncryptedChat encryptedChat = MessagesController.getInstance().encryptedChats.get((int)(dialog_id >> 32)); + currentUser = MessagesController.getInstance().users.get(encryptedChat.user_id); + } + + if (currentChat != null && currentUser != null) { + actionBarLayer.setTitle(currentChat.title); + actionBarLayer.setSubtitle(Utilities.formatName(currentUser.first_name, currentUser.last_name)); + } else if (currentUser != null) { + actionBarLayer.setTitle(Utilities.formatName(currentUser.first_name, currentUser.last_name)); + if ((int)dialog_id == 0) { + actionBarLayer.setTitleIcon(R.drawable.ic_lock_white, AndroidUtilities.dp(4)); + } else { + actionBarLayer.setTitleIcon(0, 0); + } + } + messageText.setTextSize(TypedValue.COMPLEX_UNIT_SP, MessagesController.getInstance().fontSize); + messageText.setText(currentMessageObject.messageText); + updateSubtitle(); + checkAndUpdateAvatar(); + } + + private void updateSubtitle() { + if (actionBarLayer == null) { + return; + } + if (currentChat != null || currentUser == null) { + return; + } + if (currentUser.id / 1000 != 777 && currentUser.id / 1000 != 333 && ContactsController.getInstance().contactsDict.get(currentUser.id) == null && (ContactsController.getInstance().contactsDict.size() != 0 || !ContactsController.getInstance().isLoadingContacts())) { + if (currentUser.phone != null && currentUser.phone.length() != 0) { + actionBarLayer.setTitle(PhoneFormat.getInstance().format("+" + currentUser.phone)); + } else { + actionBarLayer.setTitle(Utilities.formatName(currentUser.first_name, currentUser.last_name)); + } + } else { + actionBarLayer.setTitle(Utilities.formatName(currentUser.first_name, currentUser.last_name)); + } + CharSequence printString = MessagesController.getInstance().printingStrings.get(currentMessageObject.getDialogId()); + if (printString == null || printString.length() == 0) { + lastPrintString = null; + setTypingAnimation(false); + TLRPC.User user = MessagesController.getInstance().users.get(currentUser.id); + if (user != null) { + currentUser = user; + } + actionBarLayer.setSubtitle(LocaleController.formatUserStatus(currentUser)); + } else { + lastPrintString = printString; + actionBarLayer.setSubtitle(printString); + setTypingAnimation(true); + } + } + + private void checkAndUpdateAvatar() { + TLRPC.FileLocation newPhoto = null; + int placeHolderId = 0; + if (currentChat != null) { + TLRPC.Chat chat = MessagesController.getInstance().chats.get(currentChat.id); + if (chat == null) { + return; + } + currentChat = chat; + if (currentChat.photo != null) { + newPhoto = currentChat.photo.photo_small; + } + placeHolderId = Utilities.getGroupAvatarForId(currentChat.id); + } else if (currentUser != null) { + TLRPC.User user = MessagesController.getInstance().users.get(currentUser.id); + if (user == null) { + return; + } + currentUser = user; + if (currentUser.photo != null) { + newPhoto = currentUser.photo.photo_small; + } + placeHolderId = Utilities.getUserAvatarForId(currentUser.id); + } + if (avatarImageView != null) { + avatarImageView.setImage(newPhoto, "50_50", placeHolderId); + } + } + + private void setTypingAnimation(boolean start) { + if (actionBarLayer == null) { + return; + } + if (start) { + try { + actionBarLayer.setSubTitleIcon(R.drawable.typing_dots, AndroidUtilities.dp(4)); + AnimationDrawable mAnim = (AnimationDrawable)actionBarLayer.getSubTitleIcon(); + mAnim.setAlpha(200); + mAnim.start(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } else { + actionBarLayer.setSubTitleIcon(0, 0); + } + } + + @Override + public void onBackPressed() { + if (chatActivityEnterView.isEmojiPopupShowing()) { + chatActivityEnterView.hideEmojiPopup(); + return; + } + super.onBackPressed(); + } + + @Override + protected void onResume() { + super.onResume(); + if (chatActivityEnterView != null) { + chatActivityEnterView.setFieldFocused(true); + } + ConnectionsManager.getInstance().setAppPaused(false, false); + } + + @Override + protected void onPause() { + super.onPause(); + overridePendingTransition(0, 0); + if (chatActivityEnterView != null) { + chatActivityEnterView.hideEmojiPopup(); + chatActivityEnterView.setFieldFocused(false); + } + ConnectionsManager.getInstance().setAppPaused(true, false); + } + + @Override + public void didReceivedNotification(int id, Object... args) { + if (id == 1234) { + onFinish(); + finish(); + } else if (id == MessagesController.pushMessagesUpdated) { + getNewMessage(); + } else if (id == MessagesController.updateInterfaces) { + if (currentMessageObject == null) { + return; + } + 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 || (updateMask & MessagesController.UPDATE_MASK_CHAT_MEMBERS) != 0) { + updateSubtitle(); + } + if ((updateMask & MessagesController.UPDATE_MASK_AVATAR) != 0 || (updateMask & MessagesController.UPDATE_MASK_CHAT_AVATAR) != 0) { + checkAndUpdateAvatar(); + } + if ((updateMask & MessagesController.UPDATE_MASK_USER_PRINT) != 0) { + CharSequence printString = MessagesController.getInstance().printingStrings.get(currentMessageObject.getDialogId()); + if (lastPrintString != null && printString == null || lastPrintString == null && printString != null || lastPrintString != null && printString != null && !lastPrintString.equals(printString)) { + updateSubtitle(); + } + } + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + onFinish(); + if (wakeLock.isHeld()) { + wakeLock.release(); + } + } + + protected void onFinish() { + if (finished) { + return; + } + finished = true; + NotificationCenter.getInstance().removeObserver(this, 1234); + NotificationCenter.getInstance().removeObserver(this, MessagesController.pushMessagesUpdated); + NotificationCenter.getInstance().removeObserver(this, MessagesController.updateInterfaces); + if (chatActivityEnterView != null) { + chatActivityEnterView.onDestroy(); + } + if (wakeLock.isHeld()) { + wakeLock.release(); + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ProfileNotificationsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ProfileNotificationsActivity.java index 7acc1fbb3..506a8770e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ProfileNotificationsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ProfileNotificationsActivity.java @@ -26,15 +26,21 @@ import android.widget.AdapterView; import android.widget.ListView; import android.widget.TextView; +import org.telegram.android.MessagesController; +import org.telegram.messenger.ConnectionsManager; import org.telegram.messenger.FileLog; -import org.telegram.messenger.LocaleController; +import org.telegram.android.LocaleController; +import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; +import org.telegram.messenger.RPCRequest; +import org.telegram.messenger.TLObject; +import org.telegram.messenger.TLRPC; import org.telegram.ui.Adapters.BaseFragmentAdapter; import org.telegram.ui.Views.ActionBar.ActionBarLayer; import org.telegram.ui.Views.ActionBar.BaseFragment; import org.telegram.ui.Views.ColorPickerView; -public class ProfileNotificationsActivity extends BaseFragment { +public class ProfileNotificationsActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate { private ListView listView; private long dialog_id; @@ -50,20 +56,22 @@ public class ProfileNotificationsActivity extends BaseFragment { dialog_id = args.getLong("dialog_id"); } - @Override - public void onFragmentDestroy() { - super.onFragmentDestroy(); - } - @Override public boolean onFragmentCreate() { settingsNotificationsRow = rowCount++; settingsVibrateRow = rowCount++; settingsLedRow = rowCount++; settingsSoundRow = rowCount++; + NotificationCenter.getInstance().addObserver(this, MessagesController.notificationsSettingsUpdated); return super.onFragmentCreate(); } + @Override + public void onFragmentDestroy() { + super.onFragmentDestroy(); + NotificationCenter.getInstance().removeObserver(this, MessagesController.notificationsSettingsUpdated); + } + @Override public View createView(LayoutInflater inflater, ViewGroup container) { if (fragmentView == null) { @@ -112,6 +120,9 @@ public class ProfileNotificationsActivity extends BaseFragment { if (listView != null) { listView.invalidateViews(); } + if (i == settingsNotificationsRow) { + updateServerNotificationsSettings(); + } } }); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); @@ -211,6 +222,45 @@ public class ProfileNotificationsActivity extends BaseFragment { return fragmentView; } + public void updateServerNotificationsSettings() { + if ((int)dialog_id == 0) { + return; + } + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE); + TLRPC.TL_account_updateNotifySettings req = new TLRPC.TL_account_updateNotifySettings(); + req.settings = new TLRPC.TL_inputPeerNotifySettings(); + req.settings.sound = "default"; + req.settings.events_mask = 0; + req.settings.mute_until = preferences.getInt("notify2_" + dialog_id, 0) != 2 ? 0 : Integer.MAX_VALUE; + req.settings.show_previews = preferences.getBoolean("preview_" + dialog_id, true); + + req.peer = new TLRPC.TL_inputNotifyPeer(); + + if ((int)dialog_id < 0) { + ((TLRPC.TL_inputNotifyPeer)req.peer).peer = new TLRPC.TL_inputPeerChat(); + ((TLRPC.TL_inputNotifyPeer)req.peer).peer.chat_id = -(int)dialog_id; + } else { + TLRPC.User user = MessagesController.getInstance().users.get((int)dialog_id); + if (user == null) { + return; + } + if (user instanceof TLRPC.TL_userForeign || user instanceof TLRPC.TL_userRequest) { + ((TLRPC.TL_inputNotifyPeer)req.peer).peer = new TLRPC.TL_inputPeerForeign(); + ((TLRPC.TL_inputNotifyPeer)req.peer).peer.access_hash = user.access_hash; + } else { + ((TLRPC.TL_inputNotifyPeer)req.peer).peer = new TLRPC.TL_inputPeerContact(); + } + ((TLRPC.TL_inputNotifyPeer)req.peer).peer.user_id = (int)dialog_id; + } + + ConnectionsManager.getInstance().performRpc(req, new RPCRequest.RPCRequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + + } + }); + } + @Override public void onActivityResultFragment(int requestCode, int resultCode, Intent data) { if (resultCode == Activity.RESULT_OK) { @@ -248,6 +298,13 @@ public class ProfileNotificationsActivity extends BaseFragment { } } + @Override + public void didReceivedNotification(int id, Object... args) { + if (id == MessagesController.notificationsSettingsUpdated) { + listView.invalidateViews(); + } + } + private class ListAdapter extends BaseFragmentAdapter { private Context mContext; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/SettingsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/SettingsActivity.java index 6a86bf074..082a3d661 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/SettingsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/SettingsActivity.java @@ -34,17 +34,19 @@ import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; +import org.telegram.android.AndroidUtilities; +import org.telegram.android.ContactsController; import org.telegram.PhoneFormat.PhoneFormat; import org.telegram.messenger.BuildVars; -import org.telegram.messenger.LocaleController; +import org.telegram.android.LocaleController; import org.telegram.messenger.SerializedData; import org.telegram.messenger.TLClassStore; import org.telegram.messenger.TLObject; import org.telegram.messenger.TLRPC; import org.telegram.messenger.ConnectionsManager; import org.telegram.messenger.FileLog; -import org.telegram.messenger.MessagesController; -import org.telegram.messenger.MessagesStorage; +import org.telegram.android.MessagesController; +import org.telegram.android.MessagesStorage; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.RPCRequest; @@ -167,7 +169,7 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter }); } } - }, null, true, RPCRequest.RPCRequestClassGeneric); + }); } }; NotificationCenter.getInstance().addObserver(this, MessagesController.updateInterfaces); @@ -301,7 +303,7 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter final TextView message = new TextView(getParentActivity()); message.setText(Html.fromHtml(LocaleController.getString("AskAQuestionInfo", R.string.AskAQuestionInfo))); message.setTextSize(18); - message.setPadding(Utilities.dp(8), Utilities.dp(5), Utilities.dp(8), Utilities.dp(6)); + message.setPadding(AndroidUtilities.dp(8), AndroidUtilities.dp(5), AndroidUtilities.dp(8), AndroidUtilities.dp(6)); message.setMovementMethod(new LinkMovementMethodMy()); AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); @@ -362,7 +364,7 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter MessagesController.getInstance().registerForPush(UserConfig.pushString); ConnectionsManager.getInstance().initPushConnection(); } - }, null, true, RPCRequest.RPCRequestClassGeneric); + }); } }); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); @@ -479,7 +481,7 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter avatarImage.getLocationInWindow(coords); PhotoViewer.PlaceProviderObject object = new PhotoViewer.PlaceProviderObject(); object.viewX = coords[0]; - object.viewY = coords[1] - Utilities.statusBarHeight; + object.viewY = coords[1] - AndroidUtilities.statusBarHeight; object.parentView = listView; object.imageReceiver = avatarImage.imageReceiver; object.user_id = UserConfig.getClientUserId(); @@ -528,7 +530,9 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter if (datacentersBytes != null) { SerializedData data = new SerializedData(datacentersBytes); supportUser = (TLRPC.User)TLClassStore.Instance().TLdeserialize(data, data.readInt32()); - + if (supportUser != null && supportUser.id == 333000) { + supportUser = null; + } } } catch (Exception e) { FileLog.e("tmessages", e); @@ -583,7 +587,7 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter }); } } - }, null, true, RPCRequest.RPCRequestClassGeneric); + }); } else { MessagesController.getInstance().users.putIfAbsent(supportUser.id, supportUser); Bundle args = new Bundle(); @@ -794,7 +798,7 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter }); } } - }, null, true, RPCRequest.RPCRequestClassGeneric); + }); } } }); @@ -806,7 +810,7 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter textView.setText(LocaleController.getString("Online", R.string.Online)); textView = (TextView)view.findViewById(R.id.settings_name); - Typeface typeface = Utilities.getTypeface("fonts/rmedium.ttf"); + Typeface typeface = AndroidUtilities.getTypeface("fonts/rmedium.ttf"); textView.setTypeface(typeface); TLRPC.User user = MessagesController.getInstance().users.get(UserConfig.getClientUserId()); if (user == null) { @@ -950,12 +954,16 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE); + SharedPreferences.Editor editor = preferences.edit(); + editor.clear().commit(); NotificationCenter.getInstance().postNotificationName(1234); MessagesController.getInstance().unregistedPush(); MessagesController.getInstance().logOut(); UserConfig.clearConfig(); MessagesStorage.getInstance().cleanUp(); MessagesController.getInstance().cleanUp(); + ContactsController.getInstance().deleteAllAppAccounts(); } }); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/SettingsBlockedUsers.java b/TMessagesProj/src/main/java/org/telegram/ui/SettingsBlockedUsers.java index 0029f53c2..5d590cacf 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/SettingsBlockedUsers.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/SettingsBlockedUsers.java @@ -20,11 +20,11 @@ import android.widget.ListView; import android.widget.TextView; import org.telegram.PhoneFormat.PhoneFormat; -import org.telegram.messenger.LocaleController; +import org.telegram.android.LocaleController; import org.telegram.messenger.TLObject; import org.telegram.messenger.TLRPC; import org.telegram.messenger.ConnectionsManager; -import org.telegram.messenger.MessagesController; +import org.telegram.android.MessagesController; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.RPCRequest; @@ -148,7 +148,7 @@ public class SettingsBlockedUsers extends BaseFragment implements NotificationCe public void run(TLObject response, TLRPC.TL_error error) { } - }, null, true, RPCRequest.RPCRequestClassGeneric); + }); } } }); @@ -220,7 +220,7 @@ public class SettingsBlockedUsers extends BaseFragment implements NotificationCe } }); } - }, null, true, RPCRequest.RPCRequestClassGeneric); + }); ConnectionsManager.getInstance().bindRequestToGuid(requestId, classGuid); } @@ -273,7 +273,7 @@ public class SettingsBlockedUsers extends BaseFragment implements NotificationCe public void run(TLObject response, TLRPC.TL_error error) { } - }, null, true, RPCRequest.RPCRequestClassGeneric); + }); } private class ListAdapter extends BaseFragmentAdapter { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/SettingsChangeNameActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/SettingsChangeNameActivity.java index 15b8578d0..9b1b355f6 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/SettingsChangeNameActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/SettingsChangeNameActivity.java @@ -19,16 +19,16 @@ import android.widget.Button; import android.widget.EditText; import android.widget.TextView; -import org.telegram.messenger.LocaleController; +import org.telegram.android.AndroidUtilities; +import org.telegram.android.LocaleController; import org.telegram.messenger.TLObject; import org.telegram.messenger.TLRPC; import org.telegram.messenger.ConnectionsManager; -import org.telegram.messenger.MessagesController; +import org.telegram.android.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.Views.ActionBar.BaseFragment; public class SettingsChangeNameActivity extends BaseFragment { @@ -120,7 +120,7 @@ public class SettingsChangeNameActivity extends BaseFragment { boolean animations = preferences.getBoolean("view_animations", true); if (!animations) { firstNameField.requestFocus(); - Utilities.showKeyboard(firstNameField); + AndroidUtilities.showKeyboard(firstNameField); } } @@ -143,12 +143,12 @@ public class SettingsChangeNameActivity extends BaseFragment { public void run(TLObject response, TLRPC.TL_error error) { } - }, null, true, RPCRequest.RPCRequestClassGeneric); + }); } @Override public void onOpenAnimationEnd() { firstNameField.requestFocus(); - Utilities.showKeyboard(firstNameField); + AndroidUtilities.showKeyboard(firstNameField); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/SettingsNotificationsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/SettingsNotificationsActivity.java index c313a3d06..4e504247c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/SettingsNotificationsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/SettingsNotificationsActivity.java @@ -27,12 +27,13 @@ import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; -import org.telegram.messenger.LocaleController; +import org.telegram.android.LocaleController; +import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.TLObject; import org.telegram.messenger.TLRPC; import org.telegram.messenger.ConnectionsManager; import org.telegram.messenger.FileLog; -import org.telegram.messenger.MessagesController; +import org.telegram.android.MessagesController; import org.telegram.messenger.R; import org.telegram.messenger.RPCRequest; import org.telegram.messenger.Utilities; @@ -41,7 +42,7 @@ import org.telegram.ui.Views.ActionBar.ActionBarLayer; import org.telegram.ui.Views.ActionBar.BaseFragment; import org.telegram.ui.Views.ColorPickerView; -public class SettingsNotificationsActivity extends BaseFragment { +public class SettingsNotificationsActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate { private ListView listView; private boolean reseting = false; @@ -52,12 +53,14 @@ public class SettingsNotificationsActivity extends BaseFragment { private int messageVibrateRow; private int messageSoundRow; private int messageLedRow; + private int messagePopupNotificationRow; private int groupSectionRow; private int groupAlertRow; private int groupPreviewRow; private int groupVibrateRow; private int groupSoundRow; private int groupLedRow; + private int groupPopupNotificationRow; private int inappSectionRow; private int inappSoundRow; private int inappVibrateRow; @@ -78,12 +81,14 @@ public class SettingsNotificationsActivity extends BaseFragment { messagePreviewRow = rowCount++; messageVibrateRow = rowCount++; messageLedRow = rowCount++; + messagePopupNotificationRow = rowCount++; messageSoundRow = rowCount++; groupSectionRow = rowCount++; groupAlertRow = rowCount++; groupPreviewRow = rowCount++; groupVibrateRow = rowCount++; groupLedRow = rowCount++; + groupPopupNotificationRow = rowCount++; groupSoundRow = rowCount++; inappSectionRow = rowCount++; inappSoundRow = rowCount++; @@ -96,9 +101,17 @@ public class SettingsNotificationsActivity extends BaseFragment { resetSectionRow = rowCount++; resetNotificationsRow = rowCount++; + NotificationCenter.getInstance().addObserver(this, MessagesController.notificationsSettingsUpdated); + return super.onFragmentCreate(); } + @Override + public void onFragmentDestroy() { + super.onFragmentDestroy(); + NotificationCenter.getInstance().removeObserver(this, MessagesController.notificationsSettingsUpdated); + } + @Override public View createView(LayoutInflater inflater, ViewGroup container) { if (fragmentView == null) { @@ -134,10 +147,10 @@ public class SettingsNotificationsActivity extends BaseFragment { } editor.commit(); listView.invalidateViews(); + updateServerNotificationsSettings(i == groupAlertRow); } else if (i == messagePreviewRow || i == groupPreviewRow) { SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE); SharedPreferences.Editor editor = preferences.edit(); - boolean enabledAll = true; boolean enabled; if (i == messagePreviewRow) { enabled = preferences.getBoolean("EnablePreviewAll", true); @@ -148,6 +161,7 @@ public class SettingsNotificationsActivity extends BaseFragment { } editor.commit(); listView.invalidateViews(); + updateServerNotificationsSettings(i == groupPreviewRow); } else if (i == messageVibrateRow || i == groupVibrateRow) { SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE); SharedPreferences.Editor editor = preferences.edit(); @@ -228,7 +242,7 @@ public class SettingsNotificationsActivity extends BaseFragment { } }); } - }, null, true, RPCRequest.RPCRequestClassGeneric); + }); } else if (i == inappSoundRow) { SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE); SharedPreferences.Editor editor = preferences.edit(); @@ -342,6 +356,32 @@ public class SettingsNotificationsActivity extends BaseFragment { } }); showAlertDialog(builder); + } else if (i == messagePopupNotificationRow || i == groupPopupNotificationRow) { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString("PopupNotification", R.string.PopupNotification)); + builder.setItems(new CharSequence[] { + LocaleController.getString("NoPopup", R.string.NoPopup), + LocaleController.getString("OnlyWhenScreenOn", R.string.OnlyWhenScreenOn), + LocaleController.getString("OnlyWhenScreenOff", R.string.OnlyWhenScreenOff), + LocaleController.getString("AlwaysShowPopup", R.string.AlwaysShowPopup) + }, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE); + SharedPreferences.Editor editor = preferences.edit(); + if (i == messagePopupNotificationRow) { + editor.putInt("popupAll", which); + } else if (i == groupPopupNotificationRow) { + editor.putInt("popupGroup", which); + } + editor.commit(); + if (listView != null) { + listView.invalidateViews(); + } + } + }); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + showAlertDialog(builder); } } }); @@ -354,6 +394,29 @@ public class SettingsNotificationsActivity extends BaseFragment { return fragmentView; } + public void updateServerNotificationsSettings(boolean group) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE); + TLRPC.TL_account_updateNotifySettings req = new TLRPC.TL_account_updateNotifySettings(); + req.settings = new TLRPC.TL_inputPeerNotifySettings(); + req.settings.sound = "default"; + req.settings.events_mask = 0; + if (!group) { + req.peer = new TLRPC.TL_inputNotifyUsers(); + req.settings.mute_until = preferences.getBoolean("EnableAll", true) ? 0 : Integer.MAX_VALUE; + req.settings.show_previews = preferences.getBoolean("EnablePreviewAll", true); + } else { + req.peer = new TLRPC.TL_inputNotifyChats(); + req.settings.mute_until = preferences.getBoolean("EnableGroup", true) ? 0 : Integer.MAX_VALUE; + req.settings.show_previews = preferences.getBoolean("EnablePreviewGroup", true); + } + ConnectionsManager.getInstance().performRpc(req, new RPCRequest.RPCRequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + + } + }); + } + @Override public void onActivityResultFragment(int requestCode, int resultCode, Intent data) { if (resultCode == Activity.RESULT_OK) { @@ -396,6 +459,13 @@ public class SettingsNotificationsActivity extends BaseFragment { } } + @Override + public void didReceivedNotification(int id, Object... args) { + if (id == MessagesController.notificationsSettingsUpdated) { + listView.invalidateViews(); + } + } + private class ListAdapter extends BaseFragmentAdapter { private Context mContext; @@ -553,6 +623,24 @@ public class SettingsNotificationsActivity extends BaseFragment { textView.setText(LocaleController.getString("ResetAllNotifications", R.string.ResetAllNotifications)); textViewDetail.setText(LocaleController.getString("UndoAllCustom", R.string.UndoAllCustom)); divider.setVisibility(View.INVISIBLE); + } else if (i == messagePopupNotificationRow || i == groupPopupNotificationRow) { + textView.setText(LocaleController.getString("PopupNotification", R.string.PopupNotification)); + int option = 0; + if (i == messagePopupNotificationRow) { + option = preferences.getInt("popupAll", 0); + } else if (i == groupPopupNotificationRow) { + option = preferences.getInt("popupGroup", 0); + } + if (option == 0) { + textViewDetail.setText(LocaleController.getString("NoPopup", R.string.NoPopup)); + } else if (option == 1) { + textViewDetail.setText(LocaleController.getString("OnlyWhenScreenOn", R.string.OnlyWhenScreenOn)); + } else if (option == 2) { + textViewDetail.setText(LocaleController.getString("OnlyWhenScreenOff", R.string.OnlyWhenScreenOff)); + } else if (option == 3) { + textViewDetail.setText(LocaleController.getString("AlwaysShowPopup", R.string.AlwaysShowPopup)); + } + divider.setVisibility(View.VISIBLE); } } else if (type == 3) { if (view == null) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/SettingsWallpapersActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/SettingsWallpapersActivity.java index 088354b21..b6620d7e3 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/SettingsWallpapersActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/SettingsWallpapersActivity.java @@ -29,13 +29,14 @@ import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.TextView; -import org.telegram.messenger.LocaleController; +import org.telegram.android.AndroidUtilities; +import org.telegram.android.LocaleController; import org.telegram.messenger.TLObject; import org.telegram.messenger.TLRPC; import org.telegram.messenger.ConnectionsManager; import org.telegram.messenger.FileLoader; import org.telegram.messenger.FileLog; -import org.telegram.messenger.MessagesStorage; +import org.telegram.android.MessagesStorage; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.RPCRequest; @@ -111,8 +112,8 @@ public class SettingsWallpapersActivity extends BaseFragment implements Notifica boolean done; TLRPC.WallPaper wallPaper = wallpappersByIds.get(selectedBackground); if (wallPaper != null && wallPaper.id != 1000001 && wallPaper instanceof TLRPC.TL_wallPaper) { - int width = Utilities.displaySize.x; - int height = Utilities.displaySize.y; + int width = AndroidUtilities.displaySize.x; + int height = AndroidUtilities.displaySize.y; if (width > height) { int temp = width; width = height; @@ -120,7 +121,7 @@ public class SettingsWallpapersActivity extends BaseFragment implements Notifica } TLRPC.PhotoSize size = PhotoObject.getClosestPhotoSizeWithSize(wallPaper.sizes, width, height); String fileName = size.location.volume_id + "_" + size.location.local_id + ".jpg"; - File f = new File(Utilities.getCacheDir(), fileName); + File f = new File(AndroidUtilities.getCacheDir(), fileName); File toFile = new File(ApplicationLoader.applicationContext.getFilesDir(), "wallpaper.jpg"); try { done = Utilities.copyFile(f, toFile); @@ -216,7 +217,7 @@ public class SettingsWallpapersActivity extends BaseFragment implements Notifica if (requestCode == 10) { Utilities.addMediaToGallery(currentPicturePath); try { - Bitmap bitmap = FileLoader.loadBitmap(currentPicturePath, null, Utilities.dp(320), Utilities.dp(480)); + Bitmap bitmap = FileLoader.loadBitmap(currentPicturePath, null, AndroidUtilities.dp(320), AndroidUtilities.dp(480)); File toFile = new File(ApplicationLoader.applicationContext.getFilesDir(), "wallpaper-temp.jpg"); FileOutputStream stream = new FileOutputStream(toFile); bitmap.compress(Bitmap.CompressFormat.JPEG, 87, stream); @@ -232,7 +233,7 @@ public class SettingsWallpapersActivity extends BaseFragment implements Notifica return; } try { - Bitmap bitmap = FileLoader.loadBitmap(null, data.getData(), Utilities.dp(320), Utilities.dp(480)); + Bitmap bitmap = FileLoader.loadBitmap(null, data.getData(), AndroidUtilities.dp(320), AndroidUtilities.dp(480)); File toFile = new File(ApplicationLoader.applicationContext.getFilesDir(), "wallpaper-temp.jpg"); FileOutputStream stream = new FileOutputStream(toFile); bitmap.compress(Bitmap.CompressFormat.JPEG, 87, stream); @@ -261,8 +262,8 @@ public class SettingsWallpapersActivity extends BaseFragment implements Notifica private void processSelectedBackground() { TLRPC.WallPaper wallPaper = wallpappersByIds.get(selectedBackground); if (selectedBackground != -1 && selectedBackground != 1000001 && wallPaper != null && wallPaper instanceof TLRPC.TL_wallPaper) { - int width = Utilities.displaySize.x; - int height = Utilities.displaySize.y; + int width = AndroidUtilities.displaySize.x; + int height = AndroidUtilities.displaySize.y; if (width > height) { int temp = width; width = height; @@ -270,7 +271,7 @@ public class SettingsWallpapersActivity extends BaseFragment implements Notifica } TLRPC.PhotoSize size = PhotoObject.getClosestPhotoSizeWithSize(wallPaper.sizes, width, height); String fileName = size.location.volume_id + "_" + size.location.local_id + ".jpg"; - File f = new File(Utilities.getCacheDir(), fileName); + File f = new File(AndroidUtilities.getCacheDir(), fileName); if (!f.exists()) { progressBar.setProgress(0); loadingFile = fileName; @@ -413,7 +414,7 @@ public class SettingsWallpapersActivity extends BaseFragment implements Notifica } }); } - }, null, true, RPCRequest.RPCRequestClassGeneric); + }); ConnectionsManager.getInstance().bindRequestToGuid(reqId, classGuid); } @@ -528,7 +529,7 @@ public class SettingsWallpapersActivity extends BaseFragment implements Notifica BackupImageView image = (BackupImageView)view.findViewById(R.id.image); View selection = view.findViewById(R.id.selection); TLRPC.WallPaper wallPaper = wallPapers.get(i - 1); - TLRPC.PhotoSize size = PhotoObject.getClosestPhotoSizeWithSize(wallPaper.sizes, Utilities.dp(100), Utilities.dp(100)); + TLRPC.PhotoSize size = PhotoObject.getClosestPhotoSizeWithSize(wallPaper.sizes, AndroidUtilities.dp(100), AndroidUtilities.dp(100)); if (size != null && size.location != null) { image.setImage(size.location, "100_100", 0); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/UserProfileActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/UserProfileActivity.java index f2fe59641..63ba93f33 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/UserProfileActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/UserProfileActivity.java @@ -23,15 +23,16 @@ import android.widget.ImageButton; import android.widget.ListView; import android.widget.TextView; +import org.telegram.android.AndroidUtilities; import org.telegram.PhoneFormat.PhoneFormat; -import org.telegram.messenger.LocaleController; +import org.telegram.android.LocaleController; import org.telegram.messenger.TLObject; import org.telegram.messenger.TLRPC; import org.telegram.messenger.ConnectionsManager; -import org.telegram.messenger.ContactsController; +import org.telegram.android.ContactsController; import org.telegram.messenger.FileLog; -import org.telegram.messenger.MessagesController; -import org.telegram.messenger.MessagesStorage; +import org.telegram.android.MessagesController; +import org.telegram.android.MessagesStorage; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.RPCRequest; @@ -51,7 +52,6 @@ public class UserProfileActivity extends BaseFragment implements NotificationCen private ListView listView; private ListAdapter listAdapter; private int user_id; - private String selectedPhone; private int totalMediaCount = -1; private boolean creatingChat = false; private long dialog_id; @@ -129,7 +129,7 @@ public class UserProfileActivity extends BaseFragment implements NotificationCen actionBarLayer.setBackOverlay(R.layout.updating_state_layout); if (dialog_id != 0) { actionBarLayer.setTitle(LocaleController.getString("SecretTitle", R.string.SecretTitle)); - actionBarLayer.setTitleIcon(R.drawable.ic_lock_white, Utilities.dp(4)); + actionBarLayer.setTitleIcon(R.drawable.ic_lock_white, AndroidUtilities.dp(4)); } else { actionBarLayer.setTitle(LocaleController.getString("ContactInfo", R.string.ContactInfo)); } @@ -159,7 +159,7 @@ public class UserProfileActivity extends BaseFragment implements NotificationCen public void run(TLObject response, TLRPC.TL_error error) { } - }, null, true, RPCRequest.RPCRequestClassGeneric); + }); } }); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); @@ -384,7 +384,7 @@ public class UserProfileActivity extends BaseFragment implements NotificationCen avatarImage.getLocationInWindow(coords); PhotoViewer.PlaceProviderObject object = new PhotoViewer.PlaceProviderObject(); object.viewX = coords[0]; - object.viewY = coords[1] - Utilities.statusBarHeight; + object.viewY = coords[1] - AndroidUtilities.statusBarHeight; object.parentView = listView; object.imageReceiver = avatarImage.imageReceiver; object.user_id = user_id; @@ -533,7 +533,7 @@ public class UserProfileActivity extends BaseFragment implements NotificationCen onlineText = (TextView)view.findViewById(R.id.settings_online); } TextView textView = (TextView)view.findViewById(R.id.settings_name); - Typeface typeface = Utilities.getTypeface("fonts/rmedium.ttf"); + Typeface typeface = AndroidUtilities.getTypeface("fonts/rmedium.ttf"); textView.setTypeface(typeface); textView.setText(Utilities.formatName(user.first_name, user.last_name)); @@ -572,29 +572,20 @@ public class UserProfileActivity extends BaseFragment implements NotificationCen if (user.phone == null || user.phone.length() == 0 || getParentActivity() == null) { return; } - selectedPhone = user.phone; AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setItems(new CharSequence[] {LocaleController.getString("Copy", R.string.Copy), LocaleController.getString("Call", R.string.Call)}, new DialogInterface.OnClickListener() { + builder.setItems(new CharSequence[] {LocaleController.getString("Copy", R.string.Copy)}, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { - if (i == 1) { - try { - Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:+" + selectedPhone)); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - getParentActivity().startActivity(intent); - } catch (Exception e) { - FileLog.e("tmessages", e); - } - } else if (i == 0) { + if (i == 0) { int sdk = android.os.Build.VERSION.SDK_INT; if(sdk < android.os.Build.VERSION_CODES.HONEYCOMB) { android.text.ClipboardManager clipboard = (android.text.ClipboardManager)ApplicationLoader.applicationContext.getSystemService(Context.CLIPBOARD_SERVICE); - clipboard.setText(selectedPhone); + clipboard.setText(user.phone); } else { android.content.ClipboardManager clipboard = (android.content.ClipboardManager)ApplicationLoader.applicationContext.getSystemService(Context.CLIPBOARD_SERVICE); - android.content.ClipData clip = android.content.ClipData.newPlainText("label", selectedPhone); + android.content.ClipData clip = android.content.ClipData.newPlainText("label", user.phone); clipboard.setPrimaryClip(clip); } } @@ -603,21 +594,37 @@ public class UserProfileActivity extends BaseFragment implements NotificationCen showAlertDialog(builder); } }); - } - ImageButton button = (ImageButton)view.findViewById(R.id.settings_edit_name); - button.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - TLRPC.User user = MessagesController.getInstance().users.get(user_id); - if (user == null || user instanceof TLRPC.TL_userEmpty) { - return; + ImageButton button = (ImageButton)view.findViewById(R.id.settings_edit_name); + button.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + TLRPC.User user = MessagesController.getInstance().users.get(user_id); + if (user == null || user instanceof TLRPC.TL_userEmpty) { + return; + } + NotificationCenter.getInstance().postNotificationName(MessagesController.closeChats); + Bundle args = new Bundle(); + args.putInt("user_id", user_id); + presentFragment(new ChatActivity(args), true); } - NotificationCenter.getInstance().postNotificationName(MessagesController.closeChats); - Bundle args = new Bundle(); - args.putInt("user_id", user_id); - presentFragment(new ChatActivity(args), true); - } - }); + }); + button = (ImageButton)view.findViewById(R.id.settings_call_phone); + button.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + try { + Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:+" + user.phone)); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + getParentActivity().startActivity(intent); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + ImageButton button = (ImageButton)view.findViewById(R.id.settings_call_phone); + button.setVisibility(user.phone == null || user.phone.length() == 0 ? View.GONE : View.VISIBLE); + TextView textView = (TextView)view.findViewById(R.id.settings_row_text); TextView detailTextView = (TextView)view.findViewById(R.id.settings_row_text_detail); View divider = view.findViewById(R.id.settings_row_divider); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Views/ActionBar/ActionBar.java b/TMessagesProj/src/main/java/org/telegram/ui/Views/ActionBar/ActionBar.java index 76ae5d374..faf729a6a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Views/ActionBar/ActionBar.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Views/ActionBar/ActionBar.java @@ -19,6 +19,7 @@ import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; +import org.telegram.android.AndroidUtilities; import org.telegram.messenger.R; import org.telegram.messenger.Utilities; @@ -52,7 +53,7 @@ public class ActionBar extends FrameLayout { addView(shadowView); shadowView.setVisibility(INVISIBLE); ViewGroup.LayoutParams layoutParams = shadowView.getLayoutParams(); - layoutParams.width = Utilities.dp(2); + layoutParams.width = AndroidUtilities.dp(2); layoutParams.height = LayoutParams.MATCH_PARENT; shadowView.setLayoutParams(layoutParams); shadowView.setBackgroundResource(R.drawable.shadow); @@ -116,7 +117,7 @@ public class ActionBar extends FrameLayout { layoutParams.width = LayoutParams.MATCH_PARENT; layoutParams.height = LayoutParams.MATCH_PARENT; layer.setLayoutParams(layoutParams); - shadowView.setX(-Utilities.dp(2)); + shadowView.setX(-AndroidUtilities.dp(2)); shadowView.setVisibility(VISIBLE); previousLayer.setBackOverlayVisible(isBackOverlayVisible); } @@ -143,7 +144,7 @@ public class ActionBar extends FrameLayout { return; } currentLayer.setX(dx); - shadowView.setX(dx - Utilities.dp(2)); + shadowView.setX(dx - AndroidUtilities.dp(2)); if (dx != 0) { if (previousLayer != null) { previousLayer.setAlpha(Math.min(1, (float) dx / (float) currentLayer.getMeasuredWidth())); @@ -159,11 +160,11 @@ public class ActionBar extends FrameLayout { public void setupAnimations(ArrayList animators, boolean back) { if (back) { animators.add(ObjectAnimator.ofFloat(currentLayer, "x", 0)); - animators.add(ObjectAnimator.ofFloat(shadowView, "x", -Utilities.dp(2))); + animators.add(ObjectAnimator.ofFloat(shadowView, "x", -AndroidUtilities.dp(2))); animators.add(ObjectAnimator.ofFloat(previousLayer, "alpha", 0)); } else { animators.add(ObjectAnimator.ofFloat(currentLayer, "x", getMeasuredWidth())); - animators.add(ObjectAnimator.ofFloat(shadowView, "x", getMeasuredWidth() - Utilities.dp(2))); + animators.add(ObjectAnimator.ofFloat(shadowView, "x", getMeasuredWidth() - AndroidUtilities.dp(2))); animators.add(ObjectAnimator.ofFloat(previousLayer, "alpha", 1.0f)); } } @@ -171,9 +172,9 @@ public class ActionBar extends FrameLayout { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { if (!Utilities.isTablet(getContext()) && getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) { - super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(Utilities.dp(40), MeasureSpec.EXACTLY)); + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(40), MeasureSpec.EXACTLY)); } else { - super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(Utilities.dp(48), MeasureSpec.EXACTLY)); + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(48), MeasureSpec.EXACTLY)); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Views/ActionBar/ActionBarActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/Views/ActionBar/ActionBarActivity.java index 3cdcd8ddb..40b72321a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Views/ActionBar/ActionBarActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Views/ActionBar/ActionBarActivity.java @@ -32,6 +32,7 @@ import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.widget.FrameLayout; +import org.telegram.android.AndroidUtilities; import org.telegram.messenger.FileLog; import org.telegram.messenger.R; import org.telegram.messenger.Utilities; @@ -139,7 +140,7 @@ public class ActionBarActivity extends Activity { contentView.addView(shadowView); shadowView.setBackgroundResource(R.drawable.shadow); ViewGroup.LayoutParams layoutParams = shadowView.getLayoutParams(); - layoutParams.width = Utilities.dp(2); + layoutParams.width = AndroidUtilities.dp(2); layoutParams.height = FrameLayout.LayoutParams.MATCH_PARENT; shadowView.setLayoutParams(layoutParams); shadowView.setVisibility(View.INVISIBLE); @@ -202,7 +203,7 @@ public class ActionBarActivity extends Activity { containerViewBack.setX(0); actionBar.stopMoving(backAnimation); shadowView.setVisibility(View.INVISIBLE); - shadowView.setX(-Utilities.dp(2)); + shadowView.setX(-AndroidUtilities.dp(2)); if (!backAnimation) { BaseFragment lastFragment = fragmentsStack.get(fragmentsStack.size() - 1); lastFragment.onPause(); @@ -229,7 +230,7 @@ public class ActionBarActivity extends Activity { } } containerViewBack.setVisibility(View.GONE); - Utilities.unlockOrientation(this); + AndroidUtilities.unlockOrientation(this); startedTracking = false; animationInProgress = false; } @@ -239,7 +240,7 @@ public class ActionBarActivity extends Activity { startedTracking = true; startedTrackingX = (int) ev.getX(); shadowView.setVisibility(View.VISIBLE); - shadowView.setX(-Utilities.dp(2)); + shadowView.setX(-AndroidUtilities.dp(2)); containerViewBack.setVisibility(View.VISIBLE); beginTrackingSent = false; @@ -260,7 +261,7 @@ public class ActionBarActivity extends Activity { } lastFragment.onResume(); - Utilities.lockOrientation(this); + AndroidUtilities.lockOrientation(this); } public boolean onTouchEvent(MotionEvent ev) { @@ -284,12 +285,12 @@ public class ActionBarActivity extends Activity { int dx = Math.max(0, (int) (ev.getX() - startedTrackingX)); int dy = Math.abs((int)ev.getY() - startedTrackingY); velocityTracker.addMovement(ev); - if (maybeStartTracking && !startedTracking && dx >= Utilities.dp(10) && Math.abs(dx) / 3 > dy) { + if (maybeStartTracking && !startedTracking && dx >= AndroidUtilities.dp(10) && Math.abs(dx) / 3 > dy) { prepareForMoving(ev); } else if (startedTracking) { if (!beginTrackingSent) { if (getCurrentFocus() != null) { - Utilities.hideKeyboard(getCurrentFocus()); + AndroidUtilities.hideKeyboard(getCurrentFocus()); } BaseFragment currentFragment = fragmentsStack.get(fragmentsStack.size() - 1); currentFragment.onBeginSlide(); @@ -297,7 +298,7 @@ public class ActionBarActivity extends Activity { } actionBar.moveActionBarByX(dx); containerView.setX(dx); - shadowView.setX(dx - Utilities.dp(2)); + shadowView.setX(dx - AndroidUtilities.dp(2)); } } else if (ev != null && ev.getPointerId(0) == startedTrackingPointerId && (ev.getAction() == MotionEvent.ACTION_CANCEL || ev.getAction() == MotionEvent.ACTION_UP || ev.getAction() == MotionEvent.ACTION_POINTER_UP)) { if (velocityTracker == null) { @@ -321,11 +322,11 @@ public class ActionBarActivity extends Activity { if (!backAnimation) { distToMove = containerView.getMeasuredWidth() - x; animators.add(ObjectAnimator.ofFloat(containerView, "x", containerView.getMeasuredWidth())); - animators.add(ObjectAnimator.ofFloat(shadowView, "x", containerView.getMeasuredWidth() - Utilities.dp(2))); + animators.add(ObjectAnimator.ofFloat(shadowView, "x", containerView.getMeasuredWidth() - AndroidUtilities.dp(2))); } else { distToMove = x; animators.add(ObjectAnimator.ofFloat(containerView, "x", 0)); - animators.add(ObjectAnimator.ofFloat(shadowView, "x", -Utilities.dp(2))); + animators.add(ObjectAnimator.ofFloat(shadowView, "x", -AndroidUtilities.dp(2))); } actionBar.setupAnimations(animators, backAnimation); @@ -439,9 +440,9 @@ public class ActionBarActivity extends Activity { int height = 0; if (actionBar.getVisibility() == View.VISIBLE) { if (!Utilities.isTablet(this) && getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) { - height = Utilities.dp(40); + height = AndroidUtilities.dp(40); } else { - height = Utilities.dp(48); + height = AndroidUtilities.dp(48); } } @@ -500,7 +501,7 @@ public class ActionBarActivity extends Activity { return false; } if (getCurrentFocus() != null) { - Utilities.hideKeyboard(getCurrentFocus()); + AndroidUtilities.hideKeyboard(getCurrentFocus()); } boolean needAnimation = openAnimation != null && !forceWithoutAnimation && getSharedPreferences("mainconfig", Activity.MODE_PRIVATE).getBoolean("view_animations", true); @@ -575,7 +576,7 @@ public class ActionBarActivity extends Activity { return; } if (getCurrentFocus() != null) { - Utilities.hideKeyboard(getCurrentFocus()); + AndroidUtilities.hideKeyboard(getCurrentFocus()); } boolean needAnimation = animated && closeAnimation != null && getSharedPreferences("mainconfig", Activity.MODE_PRIVATE).getBoolean("view_animations", true); final BaseFragment currentFragment = fragmentsStack.get(fragmentsStack.size() - 1); @@ -634,6 +635,7 @@ public class ActionBarActivity extends Activity { } public void removeFragmentFromStack(BaseFragment fragment) { + fragment.onPause(); fragment.onFragmentDestroy(); fragment.setParentActivity(null); fragmentsStack.remove(fragment); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Views/ActionBar/ActionBarLayer.java b/TMessagesProj/src/main/java/org/telegram/ui/Views/ActionBar/ActionBarLayer.java index 5e8567a18..701624e00 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Views/ActionBar/ActionBarLayer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Views/ActionBar/ActionBarLayer.java @@ -21,6 +21,7 @@ import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.TextView; +import org.telegram.android.AndroidUtilities; import org.telegram.messenger.R; import org.telegram.messenger.Utilities; @@ -65,7 +66,7 @@ public class ActionBarLayer extends FrameLayout { layoutParams.height = LayoutParams.FILL_PARENT; layoutParams.gravity = Gravity.TOP | Gravity.LEFT; backButtonFrameLayout.setLayoutParams(layoutParams); - backButtonFrameLayout.setPadding(0, 0, Utilities.dp(4), 0); + backButtonFrameLayout.setPadding(0, 0, AndroidUtilities.dp(4), 0); backButtonFrameLayout.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { @@ -99,7 +100,7 @@ public class ActionBarLayer extends FrameLayout { layoutParams.width = LayoutParams.WRAP_CONTENT; layoutParams.height = LayoutParams.WRAP_CONTENT; layoutParams.gravity = Gravity.TOP | Gravity.LEFT; - layoutParams.setMargins(Utilities.dp(3), (height - backButtonImageView.getDrawable().getIntrinsicHeight()) / 2, 0, 0); + layoutParams.setMargins(AndroidUtilities.dp(3), (height - backButtonImageView.getDrawable().getIntrinsicHeight()) / 2, 0, 0); backButtonImageView.setLayoutParams(layoutParams); } } @@ -110,11 +111,11 @@ public class ActionBarLayer extends FrameLayout { if (!Utilities.isTablet(getContext()) && getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) { layoutParams.width = (int)(logoImageView.getDrawable().getIntrinsicWidth() / 1.3f); layoutParams.height = (int)(logoImageView.getDrawable().getIntrinsicHeight() / 1.3f); - layoutParams.setMargins(Utilities.dp(12), (height - layoutParams.height) / 2, 0, 0); + layoutParams.setMargins(AndroidUtilities.dp(12), (height - layoutParams.height) / 2, 0, 0); } else { layoutParams.width = logoImageView.getDrawable().getIntrinsicWidth(); layoutParams.height = logoImageView.getDrawable().getIntrinsicHeight(); - layoutParams.setMargins(Utilities.dp(12), (height - layoutParams.width) / 2, 0, 0); + layoutParams.setMargins(AndroidUtilities.dp(12), (height - layoutParams.width) / 2, 0, 0); } layoutParams.gravity = Gravity.TOP | Gravity.LEFT; logoImageView.setLayoutParams(layoutParams); @@ -122,9 +123,9 @@ public class ActionBarLayer extends FrameLayout { } private void positionTitle(int width, int height) { - int offset = Utilities.dp(2); + int offset = AndroidUtilities.dp(2); if (!Utilities.isTablet(getContext()) && getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) { - offset = Utilities.dp(1); + offset = AndroidUtilities.dp(1); } int maxTextWidth = 0; @@ -163,17 +164,17 @@ public class ActionBarLayer extends FrameLayout { int x = 0; if (logoImageView == null || logoImageView.getVisibility() == GONE) { - x = Utilities.dp(16); + x = AndroidUtilities.dp(16); } else { if (!Utilities.isTablet(getContext()) && getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) { - x = Utilities.dp(22) + (int)(logoImageView.getDrawable().getIntrinsicWidth() / 1.3f); + x = AndroidUtilities.dp(22) + (int)(logoImageView.getDrawable().getIntrinsicWidth() / 1.3f); } else { - x = Utilities.dp(22) + logoImageView.getDrawable().getIntrinsicWidth(); + x = AndroidUtilities.dp(22) + logoImageView.getDrawable().getIntrinsicWidth(); } } if (menu != null) { - maxTextWidth = Math.min(maxTextWidth, width - menu.getMeasuredWidth() - Utilities.dp(16)); + maxTextWidth = Math.min(maxTextWidth, width - menu.getMeasuredWidth() - AndroidUtilities.dp(16)); } if (titleTextView != null && titleTextView.getVisibility() == VISIBLE) { @@ -196,7 +197,7 @@ public class ActionBarLayer extends FrameLayout { } ViewGroup.LayoutParams layoutParams1 = backButtonFrameLayout.getLayoutParams(); - layoutParams1.width = x + maxTextWidth + (isSearchFieldVisible ? 0 : Utilities.dp(6)); + layoutParams1.width = x + maxTextWidth + (isSearchFieldVisible ? 0 : AndroidUtilities.dp(6)); backButtonFrameLayout.setLayoutParams(layoutParams1); } @@ -206,7 +207,7 @@ public class ActionBarLayer extends FrameLayout { } FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams)menu.getLayoutParams(); layoutParams.width = isSearchFieldVisible ? LayoutParams.MATCH_PARENT : LayoutParams.WRAP_CONTENT; - layoutParams.leftMargin = isSearchFieldVisible ? Utilities.dp(26) + logoImageView.getDrawable().getIntrinsicWidth() : 0; + layoutParams.leftMargin = isSearchFieldVisible ? AndroidUtilities.dp(26) + logoImageView.getDrawable().getIntrinsicWidth() : 0; menu.setLayoutParams(layoutParams); menu.measure(width, height); } @@ -402,7 +403,7 @@ public class ActionBarLayer extends FrameLayout { if (subTitleTextView != null) { subTitleTextView.setVisibility(visible ? GONE : VISIBLE); } - backButtonFrameLayout.setPadding(0, 0, visible ? 0 : Utilities.dp(4), 0); + backButtonFrameLayout.setPadding(0, 0, visible ? 0 : AndroidUtilities.dp(4), 0); if (visible) { oldUseLogo = logoImageView != null && logoImageView.getVisibility() == VISIBLE; setDisplayUseLogoEnabled(true, R.drawable.ic_ab_search); @@ -495,7 +496,7 @@ public class ActionBarLayer extends FrameLayout { layoutParams.height = LayoutParams.MATCH_PARENT; actionOverlay.setLayoutParams(layoutParams); actionOverlay.measure(widthMeasureSpec, heightMeasureSpec); - layoutParams.width = Math.min(actionOverlay.getMeasuredWidth() + Utilities.dp(4), widthMeasureSpec - (menu != null ? menu.getMeasuredWidth() : 0)); + layoutParams.width = Math.min(actionOverlay.getMeasuredWidth() + AndroidUtilities.dp(4), widthMeasureSpec - (menu != null ? menu.getMeasuredWidth() : 0)); actionOverlay.setLayoutParams(layoutParams); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Views/ActionBar/ActionBarMenu.java b/TMessagesProj/src/main/java/org/telegram/ui/Views/ActionBar/ActionBarMenu.java index 823eb704b..b22b439e4 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Views/ActionBar/ActionBarMenu.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Views/ActionBar/ActionBarMenu.java @@ -16,7 +16,7 @@ import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.LinearLayout; -import org.telegram.messenger.Utilities; +import org.telegram.android.AndroidUtilities; public class ActionBarMenu extends LinearLayout { @@ -68,7 +68,7 @@ public class ActionBarMenu extends LinearLayout { addView(menuItem); LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams)menuItem.getLayoutParams(); layoutParams.height = FrameLayout.LayoutParams.MATCH_PARENT; - layoutParams.width = Utilities.dp(56); + layoutParams.width = AndroidUtilities.dp(56); menuItem.setLayoutParams(layoutParams); menuItem.setOnClickListener(new OnClickListener() { @Override diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Views/ActionBar/ActionBarMenuItem.java b/TMessagesProj/src/main/java/org/telegram/ui/Views/ActionBar/ActionBarMenuItem.java index a655d93d8..e3c1117df 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Views/ActionBar/ActionBarMenuItem.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Views/ActionBar/ActionBarMenuItem.java @@ -26,6 +26,7 @@ import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; +import org.telegram.android.AndroidUtilities; import org.telegram.messenger.R; import org.telegram.messenger.Utilities; @@ -151,8 +152,8 @@ public class ActionBarMenuItem extends ImageView { delimeter.setBackgroundColor(0xffdcdcdc); popupLayout.addView(delimeter); LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams)delimeter.getLayoutParams(); - layoutParams.width = Utilities.dp(196); - layoutParams.height = Utilities.density >= 3 ? 2 : 1; + layoutParams.width = AndroidUtilities.dp(196); + layoutParams.height = AndroidUtilities.density >= 3 ? 2 : 1; delimeter.setLayoutParams(layoutParams); delimeter.setTag(100 + id); } @@ -160,19 +161,19 @@ public class ActionBarMenuItem extends ImageView { textView.setTextColor(0xff000000); textView.setBackgroundResource(R.drawable.list_selector); textView.setGravity(Gravity.CENTER_VERTICAL); - textView.setPadding(Utilities.dp(16), 0, Utilities.dp(16), 0); + textView.setPadding(AndroidUtilities.dp(16), 0, AndroidUtilities.dp(16), 0); textView.setTextSize(18); - textView.setMinWidth(Utilities.dp(196)); + textView.setMinWidth(AndroidUtilities.dp(196)); textView.setTag(id); textView.setText(text); if (icon != 0) { - textView.setCompoundDrawablePadding(Utilities.dp(12)); + textView.setCompoundDrawablePadding(AndroidUtilities.dp(12)); textView.setCompoundDrawablesWithIntrinsicBounds(getResources().getDrawable(icon), null, null, null); } popupLayout.addView(textView); LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams)textView.getLayoutParams(); layoutParams.width = LinearLayout.LayoutParams.WRAP_CONTENT; - layoutParams.height = Utilities.dp(48); + layoutParams.height = AndroidUtilities.dp(48); textView.setLayoutParams(layoutParams); textView.setOnClickListener(new OnClickListener() { @Override @@ -201,7 +202,7 @@ public class ActionBarMenuItem extends ImageView { popupWindow.setClippingEnabled(true); popupWindow.setInputMethodMode(ActionBarPopupWindow.INPUT_METHOD_NOT_NEEDED); popupWindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED); - popupLayout.measure(MeasureSpec.makeMeasureSpec(Utilities.dp(1000), MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(Utilities.dp(1000), MeasureSpec.AT_MOST)); + popupLayout.measure(MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(1000), MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(1000), MeasureSpec.AT_MOST)); } popupWindow.setFocusable(true); if (popupLayout.getMeasuredWidth() == 0) { @@ -219,7 +220,7 @@ public class ActionBarMenuItem extends ImageView { if (searchField.getVisibility() == VISIBLE) { searchField.setVisibility(GONE); setVisibility(VISIBLE); - Utilities.hideKeyboard(searchField); + AndroidUtilities.hideKeyboard(searchField); if (listener != null) { listener.onSearchCollapse(); } @@ -229,7 +230,7 @@ public class ActionBarMenuItem extends ImageView { setVisibility(GONE); searchField.setText(""); searchField.requestFocus(); - Utilities.showKeyboard(searchField); + AndroidUtilities.showKeyboard(searchField); if (listener != null) { listener.onSearchExpand(); } @@ -254,13 +255,13 @@ public class ActionBarMenuItem extends ImageView { searchField.setTextColor(0xffffffff); searchField.setSingleLine(true); searchField.setBackgroundResource(R.drawable.search_light_states); - searchField.setPadding(Utilities.dp(6), 0, Utilities.dp(6), 0); + searchField.setPadding(AndroidUtilities.dp(6), 0, AndroidUtilities.dp(6), 0); searchField.setInputType(EditorInfo.TYPE_TEXT_FLAG_NO_SUGGESTIONS); searchField.setOnEditorActionListener(new TextView.OnEditorActionListener() { @Override public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { if (actionId == EditorInfo.IME_ACTION_SEARCH || event != null && event.getAction() == KeyEvent.ACTION_UP && event.getKeyCode() == KeyEvent.KEYCODE_SEARCH) { - Utilities.hideKeyboard(searchField); + AndroidUtilities.hideKeyboard(searchField); } return false; } @@ -308,8 +309,8 @@ public class ActionBarMenuItem extends ImageView { layoutParams.weight = 1; layoutParams.width = 0; layoutParams.gravity = Gravity.CENTER_VERTICAL; - layoutParams.height = Utilities.dp(36); - layoutParams.rightMargin = Utilities.dp(4); + layoutParams.height = AndroidUtilities.dp(36); + layoutParams.rightMargin = AndroidUtilities.dp(4); searchField.setLayoutParams(layoutParams); searchField.setVisibility(GONE); } 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 0deea1222..4c765f8b6 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Views/AvatarUpdater.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Views/AvatarUpdater.java @@ -15,6 +15,7 @@ import android.net.Uri; import android.os.Bundle; import android.provider.MediaStore; +import org.telegram.android.AndroidUtilities; import org.telegram.messenger.TLRPC; import org.telegram.messenger.FileLoader; import org.telegram.messenger.FileLog; @@ -126,7 +127,7 @@ public class AvatarUpdater implements NotificationCenter.NotificationCenterDeleg } } else { UserConfig.saveConfig(false); - uploadingAvatar = Utilities.getCacheDir() + "/" + bigPhoto.location.volume_id + "_" + bigPhoto.location.local_id + ".jpg"; + uploadingAvatar = AndroidUtilities.getCacheDir() + "/" + bigPhoto.location.volume_id + "_" + bigPhoto.location.local_id + ".jpg"; NotificationCenter.getInstance().addObserver(AvatarUpdater.this, FileLoader.FileDidUpload); NotificationCenter.getInstance().addObserver(AvatarUpdater.this, FileLoader.FileDidFailUpload); FileLoader.getInstance().uploadFile(uploadingAvatar, false); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Views/BackupImageView.java b/TMessagesProj/src/main/java/org/telegram/ui/Views/BackupImageView.java index 598b4e501..7afc9c1de 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Views/BackupImageView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Views/BackupImageView.java @@ -18,8 +18,6 @@ import android.view.View; import org.telegram.messenger.TLRPC; -import java.lang.ref.WeakReference; - public class BackupImageView extends View { public ImageReceiver imageReceiver; public boolean processDetach = true; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Views/ChatActivityEnterView.java b/TMessagesProj/src/main/java/org/telegram/ui/Views/ChatActivityEnterView.java new file mode 100644 index 000000000..d908907dc --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Views/ChatActivityEnterView.java @@ -0,0 +1,643 @@ +/* + * This is the source code of Telegram for Android v. 1.4.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-2014. + */ + +package org.telegram.ui.Views; + +import android.animation.Animator; +import android.app.Activity; +import android.content.Context; +import android.content.SharedPreferences; +import android.graphics.Rect; +import android.os.PowerManager; +import android.text.Editable; +import android.text.TextWatcher; +import android.text.style.ImageSpan; +import android.view.KeyEvent; +import android.view.MotionEvent; +import android.view.Surface; +import android.view.View; +import android.view.WindowManager; +import android.view.animation.AccelerateDecelerateInterpolator; +import android.view.inputmethod.EditorInfo; +import android.view.inputmethod.InputMethodManager; +import android.widget.EditText; +import android.widget.FrameLayout; +import android.widget.ImageButton; +import android.widget.ImageView; +import android.widget.PopupWindow; +import android.widget.TextView; + +import org.telegram.android.AndroidUtilities; +import org.telegram.android.Emoji; +import org.telegram.android.LocaleController; +import org.telegram.android.MediaController; +import org.telegram.android.MessagesController; +import org.telegram.messenger.ConnectionsManager; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.R; +import org.telegram.messenger.TLRPC; +import org.telegram.ui.ApplicationLoader; + +public class ChatActivityEnterView implements NotificationCenter.NotificationCenterDelegate, SizeNotifierRelativeLayout.SizeNotifierRelativeLayoutDelegate { + + public static interface ChatActivityEnterViewDelegate { + public abstract void onMessageSend(); + public abstract void needSendTyping(); + } + + private EditText messsageEditText; + private ImageButton sendButton; + private PopupWindow emojiPopup; + private ImageView emojiButton; + private EmojiView emojiView; + private TextView recordTimeText; + private ImageButton audioSendButton; + private View recordPanel; + private View slideText; + private PowerManager.WakeLock mWakeLock = null; + private SizeNotifierRelativeLayout sizeNotifierRelativeLayout; + + private int keyboardHeight = 0; + private int keyboardHeightLand = 0; + private boolean keyboardVisible; + private boolean sendByEnter = false; + private long lastTypingTimeSend = 0; + private String lastTimeString = null; + private float startedDraggingX = -1; + private float distCanMove = AndroidUtilities.dp(80); + private boolean recordingAudio = false; + + private Activity parentActivity; + private long dialog_id; + private boolean ignoreTextChange = false; + private ChatActivityEnterViewDelegate delegate; + + public ChatActivityEnterView() { + NotificationCenter.getInstance().addObserver(this, MediaController.recordStarted); + NotificationCenter.getInstance().addObserver(this, MediaController.recordStartError); + NotificationCenter.getInstance().addObserver(this, MediaController.recordStopped); + NotificationCenter.getInstance().addObserver(this, MediaController.recordProgressChanged); + NotificationCenter.getInstance().addObserver(this, MessagesController.closeChats); + NotificationCenter.getInstance().addObserver(this, MediaController.audioDidSent); + NotificationCenter.getInstance().addObserver(this, 999); + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); + sendByEnter = preferences.getBoolean("send_by_enter", false); + } + + public void onDestroy() { + NotificationCenter.getInstance().removeObserver(this, MediaController.recordStarted); + NotificationCenter.getInstance().removeObserver(this, MediaController.recordStartError); + NotificationCenter.getInstance().removeObserver(this, MediaController.recordStopped); + NotificationCenter.getInstance().removeObserver(this, MediaController.recordProgressChanged); + NotificationCenter.getInstance().removeObserver(this, MessagesController.closeChats); + NotificationCenter.getInstance().removeObserver(this, 999); + if (mWakeLock != null) { + try { + mWakeLock.release(); + mWakeLock = null; + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + if (sizeNotifierRelativeLayout != null) { + sizeNotifierRelativeLayout.delegate = null; + sizeNotifierRelativeLayout = null; + } + } + + public void setContainerView(Activity activity, View containerView) { + parentActivity = activity; + + sizeNotifierRelativeLayout = (SizeNotifierRelativeLayout)containerView.findViewById(R.id.chat_layout); + sizeNotifierRelativeLayout.delegate = this; + + messsageEditText = (EditText)containerView.findViewById(R.id.chat_text_edit); + messsageEditText.setHint(LocaleController.getString("TypeMessage", R.string.TypeMessage)); + + sendButton = (ImageButton)containerView.findViewById(R.id.chat_send_button); + sendButton.setEnabled(false); + sendButton.setVisibility(View.INVISIBLE); + emojiButton = (ImageView)containerView.findViewById(R.id.chat_smile_button); + audioSendButton = (ImageButton)containerView.findViewById(R.id.chat_audio_send_button); + recordPanel = containerView.findViewById(R.id.record_panel); + recordTimeText = (TextView)containerView.findViewById(R.id.recording_time_text); + slideText = containerView.findViewById(R.id.slideText); + TextView textView = (TextView)containerView.findViewById(R.id.slideToCancelTextView); + textView.setText(LocaleController.getString("SlideToCancel", R.string.SlideToCancel)); + + emojiButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if (emojiPopup == null) { + showEmojiPopup(true); + } else { + showEmojiPopup(!emojiPopup.isShowing()); + } + } + }); + + messsageEditText.setOnKeyListener(new View.OnKeyListener() { + @Override + public boolean onKey(View view, int i, KeyEvent keyEvent) { + if (i == 4 && !keyboardVisible && emojiPopup != null && emojiPopup.isShowing()) { + if (keyEvent.getAction() == 1) { + showEmojiPopup(false); + } + return true; + } else if (i == KeyEvent.KEYCODE_ENTER && sendByEnter && keyEvent.getAction() == KeyEvent.ACTION_DOWN) { + sendMessage(); + return true; + } + return false; + } + }); + + messsageEditText.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if (emojiPopup != null && emojiPopup.isShowing()) { + showEmojiPopup(false); + } + } + }); + + messsageEditText.setOnEditorActionListener(new TextView.OnEditorActionListener() { + @Override + public boolean onEditorAction(TextView textView, int i, KeyEvent keyEvent) { + if (i == EditorInfo.IME_ACTION_SEND) { + sendMessage(); + return true; + } else if (sendByEnter) { + if (keyEvent != null && i == EditorInfo.IME_NULL && keyEvent.getAction() == KeyEvent.ACTION_DOWN) { + sendMessage(); + return true; + } + } + return false; + } + }); + + sendButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + sendMessage(); + } + }); + + audioSendButton.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View view, MotionEvent motionEvent) { + if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) { + startedDraggingX = -1; + MediaController.getInstance().startRecording(dialog_id); + updateAudioRecordIntefrace(); + } else if (motionEvent.getAction() == MotionEvent.ACTION_UP || motionEvent.getAction() == MotionEvent.ACTION_CANCEL) { + startedDraggingX = -1; + MediaController.getInstance().stopRecording(true); + recordingAudio = false; + updateAudioRecordIntefrace(); + } else if (motionEvent.getAction() == MotionEvent.ACTION_MOVE && recordingAudio) { + float x = motionEvent.getX(); + if (x < -distCanMove) { + MediaController.getInstance().stopRecording(false); + recordingAudio = false; + updateAudioRecordIntefrace(); + } + if(android.os.Build.VERSION.SDK_INT > 13) { + x = x + audioSendButton.getX(); + FrameLayout.LayoutParams params = (FrameLayout.LayoutParams)slideText.getLayoutParams(); + if (startedDraggingX != -1) { + float dist = (x - startedDraggingX); + params.leftMargin = AndroidUtilities.dp(30) + (int)dist; + slideText.setLayoutParams(params); + float alpha = 1.0f + dist / distCanMove; + if (alpha > 1) { + alpha = 1; + } else if (alpha < 0) { + alpha = 0; + } + slideText.setAlpha(alpha); + } + if (x <= slideText.getX() + slideText.getWidth() + AndroidUtilities.dp(30)) { + if (startedDraggingX == -1) { + startedDraggingX = x; + distCanMove = (recordPanel.getMeasuredWidth() - slideText.getMeasuredWidth() - AndroidUtilities.dp(48)) / 2.0f; + if (distCanMove <= 0) { + distCanMove = AndroidUtilities.dp(80); + } else if (distCanMove > AndroidUtilities.dp(80)) { + distCanMove = AndroidUtilities.dp(80); + } + } + } + if (params.leftMargin > AndroidUtilities.dp(30)) { + params.leftMargin = AndroidUtilities.dp(30); + slideText.setLayoutParams(params); + slideText.setAlpha(1); + startedDraggingX = -1; + } + } + } + view.onTouchEvent(motionEvent); + return true; + } + }); + + messsageEditText.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) { + + } + + @Override + public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) { + String message = getTrimmedString(charSequence.toString()); + sendButton.setEnabled(message.length() != 0); + checkSendButton(); + + if (message.length() != 0 && lastTypingTimeSend < System.currentTimeMillis() - 5000 && !ignoreTextChange) { + int currentTime = ConnectionsManager.getInstance().getCurrentTime(); + TLRPC.User currentUser = null; + if ((int)dialog_id > 0) { + currentUser = MessagesController.getInstance().users.get((int)dialog_id); + } + if (currentUser != null && currentUser.status != null && currentUser.status.expires < currentTime) { + return; + } + lastTypingTimeSend = System.currentTimeMillis(); + if (delegate != null) { + delegate.needSendTyping(); + } + } + } + + @Override + public void afterTextChanged(Editable editable) { + if (sendByEnter && editable.length() > 0 && editable.charAt(editable.length() - 1) == '\n') { + sendMessage(); + } + int i = 0; + ImageSpan[] arrayOfImageSpan = editable.getSpans(0, editable.length(), ImageSpan.class); + int j = arrayOfImageSpan.length; + while (true) { + if (i >= j) { + Emoji.replaceEmoji(editable, messsageEditText.getPaint().getFontMetricsInt(), AndroidUtilities.dp(20)); + return; + } + editable.removeSpan(arrayOfImageSpan[i]); + i++; + } + } + }); + + checkSendButton(); + } + + private void sendMessage() { + if (processSendingText(messsageEditText.getText().toString())) { + messsageEditText.setText(""); + lastTypingTimeSend = 0; + if (delegate != null) { + delegate.onMessageSend(); + } + } + } + + public boolean processSendingText(String text) { + text = getTrimmedString(text); + if (text.length() != 0) { + int count = (int)Math.ceil(text.length() / 2048.0f); + for (int a = 0; a < count; a++) { + String mess = text.substring(a * 2048, Math.min((a + 1) * 2048, text.length())); + MessagesController.getInstance().sendMessage(mess, dialog_id); + } + return true; + } + return false; + } + + private String getTrimmedString(String src) { + String result = src.trim(); + if (result.length() == 0) { + return result; + } + while (src.startsWith("\n")) { + src = src.substring(1); + } + while (src.endsWith("\n")) { + src = src.substring(0, src.length() - 1); + } + return src; + } + + private void checkSendButton() { + String message = getTrimmedString(messsageEditText.getText().toString()); + if (message.length() > 0) { + sendButton.setVisibility(View.VISIBLE); + audioSendButton.setVisibility(View.INVISIBLE); + } else { + sendButton.setVisibility(View.INVISIBLE); + audioSendButton.setVisibility(View.VISIBLE); + } + } + + private void updateAudioRecordIntefrace() { + if (recordingAudio) { + try { + if (mWakeLock == null) { + PowerManager pm = (PowerManager) ApplicationLoader.applicationContext.getSystemService(Context.POWER_SERVICE); + mWakeLock = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE, "audio record lock"); + mWakeLock.acquire(); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + AndroidUtilities.lockOrientation(parentActivity); + + recordPanel.setVisibility(View.VISIBLE); + recordTimeText.setText("00:00"); + lastTimeString = null; + if(android.os.Build.VERSION.SDK_INT > 13) { + FrameLayout.LayoutParams params = (FrameLayout.LayoutParams)slideText.getLayoutParams(); + params.leftMargin = AndroidUtilities.dp(30); + slideText.setLayoutParams(params); + slideText.setAlpha(1); + recordPanel.setX(AndroidUtilities.displaySize.x); + recordPanel.animate().setInterpolator(new AccelerateDecelerateInterpolator()).setListener(new Animator.AnimatorListener() { + @Override + public void onAnimationStart(Animator animator) { + } + + @Override + public void onAnimationEnd(Animator animator) { + recordPanel.setX(0); + } + + @Override + public void onAnimationCancel(Animator animator) { + } + + @Override + public void onAnimationRepeat(Animator animator) { + } + }).setDuration(300).translationX(0).start(); + } + } else { + if (mWakeLock != null) { + try { + mWakeLock.release(); + mWakeLock = null; + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + AndroidUtilities.unlockOrientation(parentActivity); + if(android.os.Build.VERSION.SDK_INT > 13) { + recordPanel.animate().setInterpolator(new AccelerateDecelerateInterpolator()).setListener(new Animator.AnimatorListener() { + @Override + public void onAnimationStart(Animator animator) { + + } + + @Override + public void onAnimationEnd(Animator animator) { + FrameLayout.LayoutParams params = (FrameLayout.LayoutParams)slideText.getLayoutParams(); + params.leftMargin = AndroidUtilities.dp(30); + slideText.setLayoutParams(params); + slideText.setAlpha(1); + recordPanel.setVisibility(View.GONE); + } + + @Override + public void onAnimationCancel(Animator animator) { + } + + @Override + public void onAnimationRepeat(Animator animator) { + } + }).setDuration(300).translationX(AndroidUtilities.displaySize.x).start(); + } else { + recordPanel.setVisibility(View.GONE); + } + } + } + + private void showEmojiPopup(boolean show) { + InputMethodManager localInputMethodManager = (InputMethodManager)ApplicationLoader.applicationContext.getSystemService(Context.INPUT_METHOD_SERVICE); + if (show) { + if (emojiPopup == null) { + createEmojiPopup(); + } + int currentHeight; + WindowManager manager = (WindowManager) ApplicationLoader.applicationContext.getSystemService(Activity.WINDOW_SERVICE); + int rotation = manager.getDefaultDisplay().getRotation(); + if (keyboardHeight <= 0) { + keyboardHeight = ApplicationLoader.applicationContext.getSharedPreferences("emoji", 0).getInt("kbd_height", AndroidUtilities.dp(200)); + } + if (keyboardHeightLand <= 0) { + keyboardHeightLand = ApplicationLoader.applicationContext.getSharedPreferences("emoji", 0).getInt("kbd_height_land3", AndroidUtilities.dp(200)); + } + if (rotation == Surface.ROTATION_270 || rotation == Surface.ROTATION_90) { + currentHeight = keyboardHeightLand; + } else { + currentHeight = keyboardHeight; + } + emojiPopup.setHeight(View.MeasureSpec.makeMeasureSpec(currentHeight, View.MeasureSpec.EXACTLY)); + emojiPopup.setWidth(View.MeasureSpec.makeMeasureSpec(sizeNotifierRelativeLayout.getWidth(), View.MeasureSpec.EXACTLY)); + + emojiPopup.showAtLocation(parentActivity.getWindow().getDecorView(), 83, 0, 0); + if (!keyboardVisible) { + sizeNotifierRelativeLayout.setPadding(0, 0, 0, currentHeight); + emojiButton.setImageResource(R.drawable.ic_msg_panel_hide); + return; + } + emojiButton.setImageResource(R.drawable.ic_msg_panel_kb); + return; + } + if (emojiButton != null) { + emojiButton.setImageResource(R.drawable.ic_msg_panel_smiles); + } + if (emojiPopup != null) { + emojiPopup.dismiss(); + } + if (sizeNotifierRelativeLayout != null) { + sizeNotifierRelativeLayout.post(new Runnable() { + public void run() { + if (sizeNotifierRelativeLayout != null) { + sizeNotifierRelativeLayout.setPadding(0, 0, 0, 0); + } + } + }); + } + } + + public void hideEmojiPopup() { + if (emojiPopup != null && emojiPopup.isShowing()) { + showEmojiPopup(false); + } + } + + private void createEmojiPopup() { + if (parentActivity == null) { + return; + } + emojiView = new EmojiView(parentActivity); + emojiView.setListener(new EmojiView.Listener() { + public void onBackspace() { + messsageEditText.dispatchKeyEvent(new KeyEvent(0, 67)); + } + + public void onEmojiSelected(String paramAnonymousString) { + int i = messsageEditText.getSelectionEnd(); + CharSequence localCharSequence = Emoji.replaceEmoji(paramAnonymousString, messsageEditText.getPaint().getFontMetricsInt(), AndroidUtilities.dp(20)); + messsageEditText.setText(messsageEditText.getText().insert(i, localCharSequence)); + int j = i + localCharSequence.length(); + messsageEditText.setSelection(j, j); + } + }); + emojiPopup = new PopupWindow(emojiView); + } + + public void setDelegate(ChatActivityEnterViewDelegate delegate) { + this.delegate = delegate; + } + + public void setDialogId(long id) { + dialog_id = id; + } + + public void setFieldText(String text) { + ignoreTextChange = true; + messsageEditText.setText(text); + messsageEditText.setSelection(messsageEditText.getText().length()); + ignoreTextChange = false; + } + + public void setFieldFocused(boolean focus) { + if (messsageEditText == null) { + return; + } + if (focus) { + if (!messsageEditText.isFocused()) { + messsageEditText.postDelayed(new Runnable() { + @Override + public void run() { + if (messsageEditText != null) { + messsageEditText.requestFocus(); + } + } + }, 600); + } + } else { + if (messsageEditText.isFocused() && !keyboardVisible) { + messsageEditText.clearFocus(); + } + } + } + + public boolean hasText() { + return messsageEditText != null && messsageEditText.length() > 0; + } + + public String getFieldText() { + if (messsageEditText != null && messsageEditText.length() > 0) { + return messsageEditText.getText().toString(); + } + return null; + } + + public boolean isEmojiPopupShowing() { + return emojiPopup != null && emojiPopup.isShowing(); + } + + @Override + public void onSizeChanged(int height) { + Rect localRect = new Rect(); + parentActivity.getWindow().getDecorView().getWindowVisibleDisplayFrame(localRect); + + WindowManager manager = (WindowManager) ApplicationLoader.applicationContext.getSystemService(Activity.WINDOW_SERVICE); + if (manager == null || manager.getDefaultDisplay() == null) { + return; + } + int rotation = manager.getDefaultDisplay().getRotation(); + + if (height > AndroidUtilities.dp(50)) { + if (rotation == Surface.ROTATION_270 || rotation == Surface.ROTATION_90) { + keyboardHeightLand = height; + ApplicationLoader.applicationContext.getSharedPreferences("emoji", 0).edit().putInt("kbd_height_land3", keyboardHeightLand).commit(); + } else { + keyboardHeight = height; + ApplicationLoader.applicationContext.getSharedPreferences("emoji", 0).edit().putInt("kbd_height", keyboardHeight).commit(); + } + } + + if (emojiPopup != null && emojiPopup.isShowing()) { + WindowManager wm = (WindowManager) ApplicationLoader.applicationContext.getSystemService(Context.WINDOW_SERVICE); + final WindowManager.LayoutParams layoutParams = (WindowManager.LayoutParams)emojiPopup.getContentView().getLayoutParams(); + layoutParams.width = sizeNotifierRelativeLayout.getWidth(); + if (rotation == Surface.ROTATION_270 || rotation == Surface.ROTATION_90) { + layoutParams.height = keyboardHeightLand; + } else { + layoutParams.height = keyboardHeight; + } + wm.updateViewLayout(emojiPopup.getContentView(), layoutParams); + if (!keyboardVisible) { + sizeNotifierRelativeLayout.post(new Runnable() { + @Override + public void run() { + sizeNotifierRelativeLayout.setPadding(0, 0, 0, layoutParams.height); + sizeNotifierRelativeLayout.requestLayout(); + } + }); + } + } + + boolean oldValue = keyboardVisible; + keyboardVisible = height > 0; + if (keyboardVisible && sizeNotifierRelativeLayout.getPaddingBottom() > 0) { + showEmojiPopup(false); + } else if (!keyboardVisible && keyboardVisible != oldValue && emojiPopup != null && emojiPopup.isShowing()) { + showEmojiPopup(false); + } + } + + @Override + public void didReceivedNotification(int id, Object... args) { + if (id == 999) { + if (emojiView != null) { + emojiView.invalidateViews(); + } + } else if (id == MediaController.recordProgressChanged) { + Long time = (Long)args[0] / 1000; + String str = String.format("%02d:%02d", time / 60, time % 60); + if (lastTimeString == null || !lastTimeString.equals(str)) { + if (recordTimeText != null) { + recordTimeText.setText(str); + } + } + } else if (id == MessagesController.closeChats) { + if (messsageEditText != null && messsageEditText.isFocused()) { + AndroidUtilities.hideKeyboard(messsageEditText); + } + } else if (id == MediaController.recordStartError || id == MediaController.recordStopped) { + if (recordingAudio) { + recordingAudio = false; + updateAudioRecordIntefrace(); + } + } else if (id == MediaController.recordStarted) { + if (!recordingAudio) { + recordingAudio = true; + updateAudioRecordIntefrace(); + } + } else if (id == MediaController.audioDidSent) { + if (delegate != null) { + delegate.onMessageSend(); + } + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Views/ColorPickerView.java b/TMessagesProj/src/main/java/org/telegram/ui/Views/ColorPickerView.java index 7386dea6a..7135cbfbc 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Views/ColorPickerView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Views/ColorPickerView.java @@ -29,7 +29,7 @@ import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; -import org.telegram.messenger.Utilities; +import org.telegram.android.AndroidUtilities; public class ColorPickerView extends View { @@ -105,15 +105,15 @@ public class ColorPickerView extends View { } private void init(AttributeSet attrs, int defStyle) { - mColorWheelThickness = Utilities.dp(8); - mColorWheelRadius = Utilities.dp(124); + mColorWheelThickness = AndroidUtilities.dp(8); + mColorWheelRadius = AndroidUtilities.dp(124); mPreferredColorWheelRadius = mColorWheelRadius; - mColorCenterRadius = Utilities.dp(54); + mColorCenterRadius = AndroidUtilities.dp(54); mPreferredColorCenterRadius = mColorCenterRadius; - mColorCenterHaloRadius = Utilities.dp(60); + mColorCenterHaloRadius = AndroidUtilities.dp(60); mPreferredColorCenterHaloRadius = mColorCenterHaloRadius; - mColorPointerRadius = Utilities.dp(14); - mColorPointerHaloRadius = Utilities.dp(18); + mColorPointerRadius = AndroidUtilities.dp(14); + mColorPointerHaloRadius = AndroidUtilities.dp(18); mAngle = (float) (-Math.PI / 2); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Views/EmojiView.java b/TMessagesProj/src/main/java/org/telegram/ui/Views/EmojiView.java index cb162010c..b8cb4817e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Views/EmojiView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Views/EmojiView.java @@ -24,10 +24,10 @@ import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; -import org.telegram.messenger.Emoji; -import org.telegram.messenger.LocaleController; +import org.telegram.android.AndroidUtilities; +import org.telegram.android.Emoji; +import org.telegram.android.LocaleController; import org.telegram.messenger.R; -import org.telegram.messenger.Utilities; import java.util.ArrayList; @@ -104,7 +104,7 @@ public class EmojiView extends LinearLayout { setOrientation(LinearLayout.VERTICAL); for (int i = 0; i < Emoji.data.length; i++) { GridView gridView = new GridView(getContext()); - gridView.setColumnWidth(Utilities.dpf(45.0f)); + gridView.setColumnWidth(AndroidUtilities.dpf(45.0f)); gridView.setNumColumns(-1); views.add(gridView); @@ -120,8 +120,8 @@ public class EmojiView extends LinearLayout { tabs.setViewPager(pager); tabs.setShouldExpand(true); tabs.setIndicatorColor(0xff33b5e5); - tabs.setIndicatorHeight(Utilities.dpf(2.0f)); - tabs.setUnderlineHeight(Utilities.dpf(2.0f)); + tabs.setIndicatorHeight(AndroidUtilities.dpf(2.0f)); + tabs.setUnderlineHeight(AndroidUtilities.dpf(2.0f)); tabs.setUnderlineColor(1711276032); tabs.setTabBackground(0); LinearLayout localLinearLayout = new LinearLayout(getContext()); @@ -138,7 +138,7 @@ public class EmojiView extends LinearLayout { } } }); - localLinearLayout.addView(localImageView, new LinearLayout.LayoutParams(Utilities.dpf(61.0f), LayoutParams.MATCH_PARENT)); + localLinearLayout.addView(localImageView, new LinearLayout.LayoutParams(AndroidUtilities.dpf(61.0f), LayoutParams.MATCH_PARENT)); recentsWrap = new FrameLayout(getContext()); recentsWrap.addView(views.get(0)); TextView localTextView = new TextView(getContext()); @@ -148,7 +148,7 @@ public class EmojiView extends LinearLayout { localTextView.setGravity(17); recentsWrap.addView(localTextView); views.get(0).setEmptyView(localTextView); - addView(localLinearLayout, new LinearLayout.LayoutParams(-1, Utilities.dpf(48.0f))); + addView(localLinearLayout, new LinearLayout.LayoutParams(-1, AndroidUtilities.dpf(48.0f))); addView(pager); loadRecents(); if (Emoji.data[0] == null || Emoji.data[0].length == 0) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Views/ImageReceiver.java b/TMessagesProj/src/main/java/org/telegram/ui/Views/ImageReceiver.java index 77b73196f..9b032264a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Views/ImageReceiver.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Views/ImageReceiver.java @@ -13,7 +13,6 @@ import android.graphics.Canvas; import android.graphics.Rect; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; -import android.os.Build; import android.view.View; import org.telegram.messenger.TLRPC; @@ -61,6 +60,9 @@ public class ImageReceiver { last_size = 0; currentImage = null; FileLoader.getInstance().cancelLoadingForImageView(this); + if (parentView != null) { + parentView.invalidate(); + } return; } String key; @@ -92,16 +94,13 @@ public class ImageReceiver { if (img == null) { isPlaceholder = true; FileLoader.getInstance().loadImage(path, httpUrl, this, filter, true, size); - if (parentView != null) { - parentView.invalidate(); - } } else { selfSetting = true; setImageBitmap(img, currentPath); selfSetting = false; - if (parentView != null) { - parentView.invalidate(); - } + } + if (parentView != null) { + parentView.invalidate(); } } @@ -166,9 +165,7 @@ public class ImageReceiver { } if (canDelete) { currentImage = null; - if (Build.VERSION.SDK_INT < 11) { - bitmap.recycle(); - } + bitmap.recycle(); } } else { currentImage = null; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Views/MessageActionLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Views/MessageActionLayout.java index d0e2e1367..793b45f7c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Views/MessageActionLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Views/MessageActionLayout.java @@ -10,8 +10,8 @@ package org.telegram.ui.Views; import android.widget.FrameLayout; +import org.telegram.android.AndroidUtilities; import org.telegram.messenger.R; -import org.telegram.messenger.Utilities; public class MessageActionLayout extends FrameLayout { public TightTextView messageTextView; @@ -31,7 +31,7 @@ public class MessageActionLayout extends FrameLayout { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); - setMeasuredDimension(messageTextView.linesMaxWidth + Utilities.dp(14), getMeasuredHeight()); + setMeasuredDimension(messageTextView.linesMaxWidth + AndroidUtilities.dp(14), getMeasuredHeight()); } @Override diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Views/NotificationView.java b/TMessagesProj/src/main/java/org/telegram/ui/Views/NotificationView.java deleted file mode 100644 index 3fef3f2a0..000000000 --- a/TMessagesProj/src/main/java/org/telegram/ui/Views/NotificationView.java +++ /dev/null @@ -1,326 +0,0 @@ -/* - * 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.ui.Views; - -import android.content.Context; -import android.graphics.PixelFormat; -import android.util.AttributeSet; -import android.util.TypedValue; -import android.view.Gravity; -import android.view.View; -import android.view.ViewGroup; -import android.view.WindowManager; -import android.view.animation.Animation; -import android.view.animation.AnimationUtils; -import android.widget.FrameLayout; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.TextView; - -import org.telegram.messenger.LocaleController; -import org.telegram.messenger.TLRPC; -import org.telegram.messenger.FileLog; -import org.telegram.messenger.MessagesController; -import org.telegram.messenger.NotificationCenter; -import org.telegram.messenger.R; -import org.telegram.messenger.Utilities; -import org.telegram.objects.MessageObject; -import org.telegram.ui.ApplicationLoader; - -import java.util.Timer; -import java.util.TimerTask; - -public class NotificationView extends LinearLayout { - public BackupImageView avatarImage; - public TextView nameTextView; - public TextView messageTextView; - public ImageView closeButton; - public FrameLayout textLayout; - private WindowManager.LayoutParams notificationLayoutParams; - private ViewGroup notificationParentView; - private boolean onScreen; - private Animation animShow; - private Animation animHide; - private Timer hideTimer; - private int currentChatId = 0; - private int currentUserId = 0; - private int currentEncId = 0; - private boolean isVisible; - private final Integer timerSync = 1; - - public NotificationView(Context context) { - super(context); - } - - public NotificationView(Context context, AttributeSet attrs) { - super(context, attrs); - } - - public NotificationView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - } - - @Override - protected void onFinishInflate() { - super.onFinishInflate(); - avatarImage = (BackupImageView)findViewById(R.id.avatar_image); - nameTextView = (TextView)findViewById(R.id.name_text_view); - messageTextView = (TextView)findViewById(R.id.message_text_view); - closeButton = (ImageView)findViewById(R.id.close_button); - textLayout = (FrameLayout)findViewById(R.id.text_layout); - closeButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - try { - synchronized (timerSync) { - if (hideTimer != null) { - hideTimer.cancel(); - hideTimer = null; - } - } - } catch (Exception e) { - FileLog.e("tmessages", e); - } - hide(true); - } - }); - - this.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - try { - synchronized (timerSync) { - if (hideTimer != null) { - hideTimer.cancel(); - hideTimer = null; - } - } - } catch (Exception e) { - FileLog.e("tmessages", e); - } - hide(true); - - NotificationCenter.getInstance().postNotificationName(658, currentChatId, currentUserId, currentEncId); - } - }); - - notificationParentView = new FrameLayout(getContext()); - notificationParentView.addView(this); - notificationParentView.setFocusable(false); - setFocusable(false); - WindowManager wm = (WindowManager) ApplicationLoader.applicationContext.getSystemService(Context.WINDOW_SERVICE); - notificationLayoutParams = new WindowManager.LayoutParams(); - notificationLayoutParams.height = 90; - notificationLayoutParams.format = PixelFormat.TRANSLUCENT; - notificationLayoutParams.width = WindowManager.LayoutParams.FILL_PARENT; - notificationLayoutParams.gravity = Gravity.CLIP_HORIZONTAL | Gravity.TOP; - notificationLayoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ERROR; - notificationLayoutParams.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; - isVisible = false; - wm.addView(notificationParentView, notificationLayoutParams); - notificationParentView.setVisibility(View.INVISIBLE); - - animHide = AnimationUtils.loadAnimation(ApplicationLoader.applicationContext, R.anim.slide_up); - animHide.setAnimationListener(new Animation.AnimationListener() { - public void onAnimationStart(Animation animation) { - onScreen = false; - } - - public void onAnimationRepeat(Animation animation) { - - } - - public void onAnimationEnd(Animation animation) { - setVisibility(GONE); - WindowManager wm = (WindowManager)ApplicationLoader.applicationContext.getSystemService(Context.WINDOW_SERVICE); - isVisible = false; - notificationParentView.setVisibility(View.INVISIBLE); - } - }); - - animShow = AnimationUtils.loadAnimation(ApplicationLoader.applicationContext, R.anim.slide_down); - animShow.setAnimationListener(new Animation.AnimationListener() { - public void onAnimationStart(Animation animation) { - setVisibility(VISIBLE); - onScreen = true; - } - - public void onAnimationRepeat(Animation animation) { - - } - - public void onAnimationEnd(Animation animation) { - - } - }); - } - - public void show(MessageObject object) { - TLRPC.User user = MessagesController.getInstance().users.get(object.messageOwner.from_id); - TLRPC.Chat chat = null; - long dialog_id = object.messageOwner.dialog_id; - if (object.messageOwner.to_id.chat_id != 0) { - chat = MessagesController.getInstance().chats.get(object.messageOwner.to_id.chat_id); - if (chat == null) { - return; - } - } - if (user == null) { - return; - } - if (chat != null) { - currentChatId = chat.id; - currentUserId = 0; - currentEncId = 0; - nameTextView.setText(Utilities.formatName(user.first_name, user.last_name) + " @ " + chat.title); - } else { - int lower_id = (int)dialog_id; - if (lower_id != 0 || dialog_id == 0) { - currentUserId = user.id; - currentEncId = 0; - } else { - currentUserId = 0; - currentEncId = (int)(dialog_id >> 32); - } - currentChatId = 0; - nameTextView.setText(Utilities.formatName(user.first_name, user.last_name)); - } - nameTextView.setTextColor(Utilities.getColorForId(user.id)); - messageTextView.setText(object.messageText); - TLRPC.FileLocation photo = null; - if (user.photo != null) { - photo = user.photo.photo_small; - } - avatarImage.setImage(photo, "50_50", Utilities.getUserAvatarForId(user.id)); - - try { - synchronized (timerSync) { - if (hideTimer != null) { - hideTimer.cancel(); - hideTimer = null; - } - } - hideTimer = new Timer(); - hideTimer.schedule(new TimerTask() { - @Override - public void run() { - Utilities.RunOnUIThread(new Runnable() { - @Override - public void run() { - hide(true); - } - }); - try { - synchronized (timerSync) { - if (hideTimer != null) { - hideTimer.cancel(); - hideTimer = null; - } - } - } catch (Exception e) { - FileLog.e("tmessages", e); - } - } - }, 3000); - } catch (Exception e) { - FileLog.e("tmessages", e); - } - - if (!onScreen) { - WindowManager wm = (WindowManager)ApplicationLoader.applicationContext.getSystemService(Context.WINDOW_SERVICE); - isVisible = true; - notificationParentView.setVisibility(View.VISIBLE); - startAnimation(animShow); - } - } - - public void hide(boolean animation) { - if (onScreen) { - if (animation) { - startAnimation(animHide); - } else { - try { - synchronized (timerSync) { - if (hideTimer != null) { - hideTimer.cancel(); - hideTimer = null; - } - } - } catch (Exception e) { - FileLog.e("tmessages", e); - } - onScreen = false; - setVisibility(GONE); - if (notificationParentView != null && notificationParentView.getParent() != null) { - WindowManager wm = (WindowManager)ApplicationLoader.applicationContext.getSystemService(Context.WINDOW_SERVICE); - isVisible = false; - notificationParentView.setVisibility(View.INVISIBLE); - } - } - } - } - - public void destroy() { - try { - if (notificationParentView != null) { - notificationParentView.removeView(this); - try { - if (notificationParentView.getParent() != null) { - WindowManager wm = (WindowManager)ApplicationLoader.applicationContext.getSystemService(Context.WINDOW_SERVICE); - wm.removeViewImmediate(notificationParentView); - } - } catch (Exception e) { - FileLog.e("tmessages", e); - } - } - notificationParentView = null; - notificationLayoutParams = null; - } catch (Exception e) { - FileLog.e("tmessages", e); - } - } - - public void applyOrientationPaddings(boolean isLandscape, int height) { - FrameLayout.LayoutParams params = (FrameLayout.LayoutParams)avatarImage.getLayoutParams(); - params.width = height; - params.height = height; - avatarImage.setLayoutParams(params); - FrameLayout.LayoutParams params1 = (FrameLayout.LayoutParams)textLayout.getLayoutParams(); - if (isLandscape) { - nameTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14); - messageTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14); - nameTextView.setPadding(0, Utilities.dp(2), 0, 0); - messageTextView.setPadding(0, Utilities.dp(18), 0, 0); - if (LocaleController.isRTL) { - params1.setMargins(Utilities.dp(40), 0, height + Utilities.dp(6), 0); - } else { - params1.setMargins(height + Utilities.dp(6), 0, Utilities.dp(40), 0); - } - } else { - nameTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 15); - messageTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 15); - nameTextView.setPadding(0, Utilities.dp(4), 0, 0); - messageTextView.setPadding(0, Utilities.dp(24), 0, 0); - if (LocaleController.isRTL) { - params1.setMargins(Utilities.dp(40), 0, height + Utilities.dp(8), 0); - } else { - params1.setMargins(height + Utilities.dp(8), 0, Utilities.dp(40), 0); - } - } - textLayout.setLayoutParams(params1); - - if (notificationParentView != null) { - notificationLayoutParams.height = height; - if (notificationParentView.getParent() != null) { - WindowManager wm = (WindowManager) ApplicationLoader.applicationContext.getSystemService(Context.WINDOW_SERVICE); - wm.updateViewLayout(notificationParentView, notificationLayoutParams); - } - } - } -} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Views/ProgressView.java b/TMessagesProj/src/main/java/org/telegram/ui/Views/ProgressView.java index cc6e95013..671c858f2 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Views/ProgressView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Views/ProgressView.java @@ -11,7 +11,7 @@ package org.telegram.ui.Views; import android.graphics.Canvas; import android.graphics.Paint; -import org.telegram.messenger.Utilities; +import org.telegram.android.AndroidUtilities; public class ProgressView { private Paint innerPaint; @@ -20,7 +20,7 @@ public class ProgressView { public float currentProgress = 0; public int width; public int height; - public float progressHeight = Utilities.dpf(2.0f); + public float progressHeight = AndroidUtilities.dpf(2.0f); public ProgressView() { innerPaint = new Paint(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Views/SeekBar.java b/TMessagesProj/src/main/java/org/telegram/ui/Views/SeekBar.java index 268e6173d..37543fc27 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Views/SeekBar.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Views/SeekBar.java @@ -14,8 +14,8 @@ import android.graphics.Paint; import android.graphics.drawable.Drawable; import android.view.MotionEvent; +import org.telegram.android.AndroidUtilities; import org.telegram.messenger.R; -import org.telegram.messenger.Utilities; public class SeekBar { @@ -121,8 +121,8 @@ public class SeekBar { outer = outerPaint2; } 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); + canvas.drawRect(thumbWidth / 2, height / 2 - AndroidUtilities.dp(1), width - thumbWidth / 2, height / 2 + AndroidUtilities.dp(1), inner); + canvas.drawRect(thumbWidth / 2, height / 2 - AndroidUtilities.dp(1), thumbWidth / 2 + thumbX, height / 2 + AndroidUtilities.dp(1), outer); thumb.setBounds(thumbX, y, thumbX + thumbWidth, y + thumbHeight); thumb.draw(canvas); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Views/SizeNotifierRelativeLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Views/SizeNotifierRelativeLayout.java index 13b594bd9..41667658c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Views/SizeNotifierRelativeLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Views/SizeNotifierRelativeLayout.java @@ -14,7 +14,7 @@ import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.widget.RelativeLayout; -import org.telegram.messenger.Utilities; +import org.telegram.android.AndroidUtilities; public class SizeNotifierRelativeLayout extends RelativeLayout { @@ -50,7 +50,7 @@ public class SizeNotifierRelativeLayout extends RelativeLayout { protected void onLayout(boolean changed, int l, int t, int r, int b) { super.onLayout(changed, l, t, r, b); if (delegate != null) { - int usableViewHeight = this.getRootView().getHeight() - Utilities.statusBarHeight; + int usableViewHeight = this.getRootView().getHeight() - AndroidUtilities.statusBarHeight; this.getWindowVisibleDisplayFrame(rect); int keyboardHeight = usableViewHeight - (rect.bottom - rect.top); delegate.onSizeChanged(keyboardHeight); @@ -60,15 +60,17 @@ public class SizeNotifierRelativeLayout extends RelativeLayout { @Override protected void onDraw(Canvas canvas) { if (backgroundDrawable != null) { - float scaleX = (float)Utilities.displaySize.x / (float)backgroundDrawable.getIntrinsicWidth(); - float scaleY = (float)Utilities.displaySize.y / (float)backgroundDrawable.getIntrinsicHeight(); + float scaleX = (float)AndroidUtilities.displaySize.x / (float)backgroundDrawable.getIntrinsicWidth(); + float scaleY = (float)AndroidUtilities.displaySize.y / (float)backgroundDrawable.getIntrinsicHeight(); float scale = scaleX < scaleY ? scaleY : scaleX; int width = (int)Math.ceil(backgroundDrawable.getIntrinsicWidth() * scale); int height = (int)Math.ceil(backgroundDrawable.getIntrinsicHeight() * scale); - int x = (Utilities.displaySize.x - width) / 2; - int y = (Utilities.displaySize.y - height) / 2; + int x = (AndroidUtilities.displaySize.x - width) / 2; + int y = (AndroidUtilities.displaySize.y - height) / 2; backgroundDrawable.setBounds(x, y, x + width, y + height); backgroundDrawable.draw(canvas); + } else { + super.onDraw(canvas); } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Views/TimerButton.java b/TMessagesProj/src/main/java/org/telegram/ui/Views/TimerButton.java index 3bf8abd07..25257a58d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Views/TimerButton.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Views/TimerButton.java @@ -19,9 +19,9 @@ import android.text.TextPaint; import android.util.AttributeSet; import android.view.View; +import org.telegram.android.AndroidUtilities; import org.telegram.messenger.FileLog; import org.telegram.messenger.R; -import org.telegram.messenger.Utilities; public class TimerButton extends View { @@ -38,7 +38,7 @@ public class TimerButton extends View { emptyTimerDrawable = getResources().getDrawable(R.drawable.header_timer); timerDrawable = getResources().getDrawable(R.drawable.header_timer2); timePaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); - timePaint.setTextSize(Utilities.dp(10)); + timePaint.setTextSize(AndroidUtilities.dp(10)); timePaint.setColor(0xffd7e8f7); timePaint.setTypeface(Typeface.DEFAULT_BOLD); } @@ -110,7 +110,7 @@ public class TimerButton extends View { drawable.draw(canvas); if (time != 0 && timeLayout != null) { - canvas.translate((width - timeWidth) / 2, (height - timeHeight) / 2 + Utilities.dp(1)); + canvas.translate((width - timeWidth) / 2, (height - timeHeight) / 2 + AndroidUtilities.dp(1)); timeLayout.draw(canvas); } } diff --git a/TMessagesProj/src/main/res/layout-ar/user_profile_phone_layout.xml b/TMessagesProj/src/main/res/layout-ar/user_profile_phone_layout.xml index 86fc6f1be..544b7294c 100644 --- a/TMessagesProj/src/main/res/layout-ar/user_profile_phone_layout.xml +++ b/TMessagesProj/src/main/res/layout-ar/user_profile_phone_layout.xml @@ -22,6 +22,17 @@ android:layout_gravity="left|center_vertical" android:layout_marginLeft="48dp"/> + + + + + + \ No newline at end of file diff --git a/TMessagesProj/src/main/res/layout/popup_notification_layout.xml b/TMessagesProj/src/main/res/layout/popup_notification_layout.xml new file mode 100644 index 000000000..4bc0597ab --- /dev/null +++ b/TMessagesProj/src/main/res/layout/popup_notification_layout.xml @@ -0,0 +1,187 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/TMessagesProj/src/main/res/layout/user_profile_phone_layout.xml b/TMessagesProj/src/main/res/layout/user_profile_phone_layout.xml index ff654495d..3b8b75597 100644 --- a/TMessagesProj/src/main/res/layout/user_profile_phone_layout.xml +++ b/TMessagesProj/src/main/res/layout/user_profile_phone_layout.xml @@ -30,6 +30,17 @@ android:textAllCaps="true" android:layout_gravity="bottom"/> + + الاسم الأول
اسم العائلة LED Color + Popup Notification + No popup + Only when screen "on" + Only when screen "off" + Always show popup لا توجد وسائط بعد diff --git a/TMessagesProj/src/main/res/values-de/strings.xml b/TMessagesProj/src/main/res/values-de/strings.xml index 16e4137e4..1f6fdc2c6 100644 --- a/TMessagesProj/src/main/res/values-de/strings.xml +++ b/TMessagesProj/src/main/res/values-de/strings.xml @@ -274,6 +274,11 @@ Vorname Nachname LED Farbe + Popup Notification + No popup + Only when screen "on" + Only when screen "off" + Always show popup Noch keine geteilten Medien vorhanden diff --git a/TMessagesProj/src/main/res/values-es/strings.xml b/TMessagesProj/src/main/res/values-es/strings.xml index 0b101766c..913d7583b 100644 --- a/TMessagesProj/src/main/res/values-es/strings.xml +++ b/TMessagesProj/src/main/res/values-es/strings.xml @@ -274,6 +274,11 @@ Nombre Apellido Color del LED + Popup Notification + No popup + Only when screen "on" + Only when screen "off" + Always show popup No hay fotos ni vídeos compartidos aún diff --git a/TMessagesProj/src/main/res/values-it/strings.xml b/TMessagesProj/src/main/res/values-it/strings.xml index fcb8cf810..8d1f05d62 100644 --- a/TMessagesProj/src/main/res/values-it/strings.xml +++ b/TMessagesProj/src/main/res/values-it/strings.xml @@ -274,6 +274,11 @@ Nome Cognome LED Color + Popup Notification + No popup + Only when screen "on" + Only when screen "off" + Always show popup Nessun media condiviso diff --git a/TMessagesProj/src/main/res/values-nl/strings.xml b/TMessagesProj/src/main/res/values-nl/strings.xml index abe731836..1e027d649 100644 --- a/TMessagesProj/src/main/res/values-nl/strings.xml +++ b/TMessagesProj/src/main/res/values-nl/strings.xml @@ -274,6 +274,11 @@ Voornaam Achternaam LED Color + Popup Notification + No popup + Only when screen "on" + Only when screen "off" + Always show popup Nog geen media gedeeld diff --git a/TMessagesProj/src/main/res/values-pt-rBR/strings.xml b/TMessagesProj/src/main/res/values-pt-rBR/strings.xml index 40fcdb908..40f1347a4 100644 --- a/TMessagesProj/src/main/res/values-pt-rBR/strings.xml +++ b/TMessagesProj/src/main/res/values-pt-rBR/strings.xml @@ -274,6 +274,11 @@ Primeiro nome Sobrenome LED Color + Popup Notification + No popup + Only when screen "on" + Only when screen "off" + Always show popup Ainda não há mídia compartilhada diff --git a/TMessagesProj/src/main/res/values-pt-rPT/strings.xml b/TMessagesProj/src/main/res/values-pt-rPT/strings.xml index 110e2c476..e7739fea3 100644 --- a/TMessagesProj/src/main/res/values-pt-rPT/strings.xml +++ b/TMessagesProj/src/main/res/values-pt-rPT/strings.xml @@ -274,6 +274,11 @@ Nome Apelidos LED Color + Popup Notification + No popup + Only when screen "on" + Only when screen "off" + Always show popup Ainda não há multimédia partilhado diff --git a/TMessagesProj/src/main/res/values/strings.xml b/TMessagesProj/src/main/res/values/strings.xml index 8030a4c68..e8955b691 100644 --- a/TMessagesProj/src/main/res/values/strings.xml +++ b/TMessagesProj/src/main/res/values/strings.xml @@ -274,6 +274,11 @@ First name Last name LED Color + Popup Notification + No popup + Only when screen "on" + Only when screen "off" + Always show popup No shared media yet diff --git a/TMessagesProj/src/main/res/values/styles.xml b/TMessagesProj/src/main/res/values/styles.xml index 2f71635a7..247018e30 100644 --- a/TMessagesProj/src/main/res/values/styles.xml +++ b/TMessagesProj/src/main/res/values/styles.xml @@ -7,13 +7,14 @@ @style/ActionBar.Transparent.TMessages.Start @android:color/white @android:color/white - @drawable/shadow + @null + +