1
0
mirror of https://github.com/MGislv/NekoX.git synced 2024-06-30 10:14:04 +00:00

Update to 1.3.26

Applied patch from https://github.com/DrKLO/Telegram/pull/99 . Thanks.
Added German localization. Thanks to all from
https://github.com/DrKLO/Telegram/pull/129
Experimental audio (will not go to market yet, we will switch to opus
codec)
Improved text drawing perfomance (now Telegram can draw even «War and
Peace» in one message)
Ability to send multiple photos and documents from external apps
Contacts fixes
Memory usage optimizations in network code (receiving data)
Partly switched to native ByteBuffers (decoding received data)
Added support of Telegram API Layer 12
Bug fixes
This commit is contained in:
DrKLO 2014-03-01 02:28:25 +04:00
parent 9aeb8be893
commit a21494ade6
141 changed files with 15643 additions and 10767 deletions

View File

@ -7,7 +7,7 @@
#include "aes.h"
#include "log.h"
JNIEXPORT jbyteArray Java_org_telegram_messenger_Utilities_aesIgeEncryption(JNIEnv *env, jclass class, jbyteArray _what, jbyteArray _key, jbyteArray _iv, jboolean encrypt, jboolean changeIv) {
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);
@ -20,7 +20,7 @@ JNIEXPORT jbyteArray Java_org_telegram_messenger_Utilities_aesIgeEncryption(JNIE
iv = __iv;
}
int len = (*env)->GetArrayLength(env, _what);
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);
@ -40,6 +40,36 @@ JNIEXPORT jbyteArray Java_org_telegram_messenger_Utilities_aesIgeEncryption(JNIE
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;
}
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);
} 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);
}
}
uint64_t gcd(uint64_t a, uint64_t b){
while(a != 0 && b != 0) {
while((b & 1) == 0) b >>= 1;

File diff suppressed because it is too large Load Diff

View File

@ -107,9 +107,9 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
#define SQLITE_VERSION "3.8.1"
#define SQLITE_VERSION_NUMBER 3008001
#define SQLITE_SOURCE_ID "2013-10-17 12:57:35 c78be6d786c19073b3a6730dfe3fb1be54f5657a"
#define SQLITE_VERSION "3.8.3.1"
#define SQLITE_VERSION_NUMBER 3008003
#define SQLITE_SOURCE_ID "2014-02-11 14:52:19 ea3317a4803d71d88183b29f1d3086f46d68a00e"
/*
** CAPI3REF: Run-Time Library Version Numbers
@ -370,7 +370,7 @@ typedef int (*sqlite3_callback)(void*,int,char**, char**);
** <ul>
** <li> The application must insure that the 1st parameter to sqlite3_exec()
** is a valid and open [database connection].
** <li> The application must not close [database connection] specified by
** <li> The application must not close the [database connection] specified by
** the 1st parameter to sqlite3_exec() while sqlite3_exec() is running.
** <li> The application must not modify the SQL statement text passed into
** the 2nd parameter of sqlite3_exec() while sqlite3_exec() is running.
@ -447,7 +447,7 @@ SQLITE_API int sqlite3_exec(
** [sqlite3_extended_result_codes()] API.
**
** Some of the available extended result codes are listed here.
** One may expect the number of extended result codes will be expand
** One may expect the number of extended result codes will increase
** over time. Software that uses extended result codes should expect
** to see new result codes in future releases of SQLite.
**
@ -491,6 +491,7 @@ SQLITE_API int sqlite3_exec(
#define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8))
#define SQLITE_READONLY_CANTLOCK (SQLITE_READONLY | (2<<8))
#define SQLITE_READONLY_ROLLBACK (SQLITE_READONLY | (3<<8))
#define SQLITE_READONLY_DBMOVED (SQLITE_READONLY | (4<<8))
#define SQLITE_ABORT_ROLLBACK (SQLITE_ABORT | (2<<8))
#define SQLITE_CONSTRAINT_CHECK (SQLITE_CONSTRAINT | (1<<8))
#define SQLITE_CONSTRAINT_COMMITHOOK (SQLITE_CONSTRAINT | (2<<8))
@ -501,6 +502,7 @@ SQLITE_API int sqlite3_exec(
#define SQLITE_CONSTRAINT_TRIGGER (SQLITE_CONSTRAINT | (7<<8))
#define SQLITE_CONSTRAINT_UNIQUE (SQLITE_CONSTRAINT | (8<<8))
#define SQLITE_CONSTRAINT_VTAB (SQLITE_CONSTRAINT | (9<<8))
#define SQLITE_CONSTRAINT_ROWID (SQLITE_CONSTRAINT |(10<<8))
#define SQLITE_NOTICE_RECOVER_WAL (SQLITE_NOTICE | (1<<8))
#define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8))
#define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1<<8))
@ -557,7 +559,8 @@ SQLITE_API int sqlite3_exec(
** after reboot following a crash or power loss, the only bytes in a
** file that were written at the application level might have changed
** and that adjacent bytes, even bytes within the same sector are
** guaranteed to be unchanged.
** guaranteed to be unchanged. The SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN
** flag indicate that a file cannot be deleted when open.
*/
#define SQLITE_IOCAP_ATOMIC 0x00000001
#define SQLITE_IOCAP_ATOMIC512 0x00000002
@ -788,15 +791,29 @@ struct sqlite3_io_methods {
** additional information.
**
** <li>[[SQLITE_FCNTL_SYNC_OMITTED]]
** ^(The [SQLITE_FCNTL_SYNC_OMITTED] opcode is generated internally by
** SQLite and sent to all VFSes in place of a call to the xSync method
** when the database connection has [PRAGMA synchronous] set to OFF.)^
** Some specialized VFSes need this signal in order to operate correctly
** when [PRAGMA synchronous | PRAGMA synchronous=OFF] is set, but most
** VFSes do not need this signal and should silently ignore this opcode.
** Applications should not call [sqlite3_file_control()] with this
** opcode as doing so may disrupt the operation of the specialized VFSes
** that do require it.
** No longer in use.
**
** <li>[[SQLITE_FCNTL_SYNC]]
** The [SQLITE_FCNTL_SYNC] opcode is generated internally by SQLite and
** sent to the VFS immediately before the xSync method is invoked on a
** database file descriptor. Or, if the xSync method is not invoked
** because the user has configured SQLite with
** [PRAGMA synchronous | PRAGMA synchronous=OFF] it is invoked in place
** of the xSync method. In most cases, the pointer argument passed with
** this file-control is NULL. However, if the database file is being synced
** as part of a multi-database commit, the argument points to a nul-terminated
** string containing the transactions master-journal file name. VFSes that
** do not need this signal should silently ignore this opcode. Applications
** should not call [sqlite3_file_control()] with this opcode as doing so may
** disrupt the operation of the specialized VFSes that do require it.
**
** <li>[[SQLITE_FCNTL_COMMIT_PHASETWO]]
** The [SQLITE_FCNTL_COMMIT_PHASETWO] opcode is generated internally by SQLite
** and sent to the VFS after a transaction has been committed immediately
** but before the database is unlocked. VFSes that do not need this signal
** should silently ignore this opcode. Applications should not call
** [sqlite3_file_control()] with this opcode as doing so may disrupt the
** operation of the specialized VFSes that do require it.
**
** <li>[[SQLITE_FCNTL_WIN32_AV_RETRY]]
** ^The [SQLITE_FCNTL_WIN32_AV_RETRY] opcode is used to configure automatic
@ -912,6 +929,20 @@ struct sqlite3_io_methods {
** can be queried by passing in a pointer to a negative number. This
** file-control is used internally to implement [PRAGMA mmap_size].
**
** <li>[[SQLITE_FCNTL_TRACE]]
** The [SQLITE_FCNTL_TRACE] file control provides advisory information
** to the VFS about what the higher layers of the SQLite stack are doing.
** This file control is used by some VFS activity tracing [shims].
** The argument is a zero-terminated string. Higher layers in the
** SQLite stack may generate instances of this file control if
** the [SQLITE_USE_FCNTL_TRACE] compile-time option is enabled.
**
** <li>[[SQLITE_FCNTL_HAS_MOVED]]
** The [SQLITE_FCNTL_HAS_MOVED] file control interprets its argument as a
** pointer to an integer and it writes a boolean into that integer depending
** on whether or not the file has been renamed, moved, or deleted since it
** was first opened.
**
** </ul>
*/
#define SQLITE_FCNTL_LOCKSTATE 1
@ -931,6 +962,10 @@ struct sqlite3_io_methods {
#define SQLITE_FCNTL_BUSYHANDLER 15
#define SQLITE_FCNTL_TEMPFILENAME 16
#define SQLITE_FCNTL_MMAP_SIZE 18
#define SQLITE_FCNTL_TRACE 19
#define SQLITE_FCNTL_HAS_MOVED 20
#define SQLITE_FCNTL_SYNC 21
#define SQLITE_FCNTL_COMMIT_PHASETWO 22
/*
** CAPI3REF: Mutex Handle
@ -1375,7 +1410,7 @@ SQLITE_API int sqlite3_db_config(sqlite3*, int op, ...);
** or [sqlite3_realloc()] first calls xRoundup. If xRoundup returns 0,
** that causes the corresponding memory allocation to fail.
**
** The xInit method initializes the memory allocator. (For example,
** The xInit method initializes the memory allocator. For example,
** it might allocate any require mutexes or initialize internal data
** structures. The xShutdown method is invoked (indirectly) by
** [sqlite3_shutdown()] and should deallocate any resources acquired
@ -1677,6 +1712,13 @@ struct sqlite3_mem_methods {
** [SQLITE_MAX_MMAP_SIZE] compile-time option.)^
** ^If either argument to this option is negative, then that argument is
** changed to its compile-time default.
**
** [[SQLITE_CONFIG_WIN32_HEAPSIZE]]
** <dt>SQLITE_CONFIG_WIN32_HEAPSIZE
** <dd>^This option is only available if SQLite is compiled for Windows
** with the [SQLITE_WIN32_MALLOC] pre-processor macro defined.
** SQLITE_CONFIG_WIN32_HEAPSIZE takes a 32-bit unsigned integer value
** that specifies the maximum size of the created heap.
** </dl>
*/
#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
@ -1701,6 +1743,7 @@ struct sqlite3_mem_methods {
#define SQLITE_CONFIG_COVERING_INDEX_SCAN 20 /* int */
#define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */
#define SQLITE_CONFIG_MMAP_SIZE 22 /* sqlite3_int64, sqlite3_int64 */
#define SQLITE_CONFIG_WIN32_HEAPSIZE 23 /* int nByte */
/*
** CAPI3REF: Database Connection Configuration Options
@ -1777,19 +1820,21 @@ SQLITE_API int sqlite3_extended_result_codes(sqlite3*, int onoff);
/*
** CAPI3REF: Last Insert Rowid
**
** ^Each entry in an SQLite table has a unique 64-bit signed
** ^Each entry in most SQLite tables (except for [WITHOUT ROWID] tables)
** has a unique 64-bit signed
** integer key called the [ROWID | "rowid"]. ^The rowid is always available
** as an undeclared column named ROWID, OID, or _ROWID_ as long as those
** names are not also used by explicitly declared columns. ^If
** the table has a column of type [INTEGER PRIMARY KEY] then that column
** is another alias for the rowid.
**
** ^This routine returns the [rowid] of the most recent
** successful [INSERT] into the database from the [database connection]
** in the first argument. ^As of SQLite version 3.7.7, this routines
** records the last insert rowid of both ordinary tables and [virtual tables].
** ^If no successful [INSERT]s
** have ever occurred on that database connection, zero is returned.
** ^The sqlite3_last_insert_rowid(D) interface returns the [rowid] of the
** most recent successful [INSERT] into a rowid table or [virtual table]
** on database connection D.
** ^Inserts into [WITHOUT ROWID] tables are not recorded.
** ^If no successful [INSERT]s into rowid tables
** have ever occurred on the database connection D,
** then sqlite3_last_insert_rowid(D) returns zero.
**
** ^(If an [INSERT] occurs within a trigger or within a [virtual table]
** method, then this routine will return the [rowid] of the inserted
@ -2355,11 +2400,13 @@ SQLITE_API sqlite3_int64 sqlite3_memory_highwater(int resetFlag);
** applications to access the same PRNG for other purposes.
**
** ^A call to this routine stores N bytes of randomness into buffer P.
** ^If N is less than one, then P can be a NULL pointer.
**
** ^The first time this routine is invoked (either internally or by
** the application) the PRNG is seeded using randomness obtained
** from the xRandomness method of the default [sqlite3_vfs] object.
** ^On all subsequent invocations, the pseudo-randomness is generated
** ^If this routine has not been previously called or if the previous
** call had N less than one, then the PRNG is seeded using randomness
** obtained from the xRandomness method of the default [sqlite3_vfs] object.
** ^If the previous call to this routine had an N of 1 or more then
** the pseudo-randomness is generated
** internally and without recourse to the [sqlite3_vfs] xRandomness
** method.
*/
@ -2519,6 +2566,7 @@ SQLITE_API int sqlite3_set_authorizer(
#define SQLITE_FUNCTION 31 /* NULL Function Name */
#define SQLITE_SAVEPOINT 32 /* Operation Savepoint Name */
#define SQLITE_COPY 0 /* No longer used */
#define SQLITE_RECURSIVE 33 /* NULL NULL */
/*
** CAPI3REF: Tracing And Profiling Functions
@ -3099,7 +3147,6 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
** choice of query plan if the parameter is the left-hand side of a [LIKE]
** or [GLOB] operator or if the parameter is compared to an indexed column
** and the [SQLITE_ENABLE_STAT3] compile-time option is enabled.
** the
** </li>
** </ol>
*/
@ -3761,19 +3808,19 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
**
** <tr><td> NULL <td> INTEGER <td> Result is 0
** <tr><td> NULL <td> FLOAT <td> Result is 0.0
** <tr><td> NULL <td> TEXT <td> Result is NULL pointer
** <tr><td> NULL <td> BLOB <td> Result is NULL pointer
** <tr><td> NULL <td> TEXT <td> Result is a NULL pointer
** <tr><td> NULL <td> BLOB <td> Result is a NULL pointer
** <tr><td> INTEGER <td> FLOAT <td> Convert from integer to float
** <tr><td> INTEGER <td> TEXT <td> ASCII rendering of the integer
** <tr><td> INTEGER <td> BLOB <td> Same as INTEGER->TEXT
** <tr><td> FLOAT <td> INTEGER <td> Convert from float to integer
** <tr><td> FLOAT <td> INTEGER <td> [CAST] to INTEGER
** <tr><td> FLOAT <td> TEXT <td> ASCII rendering of the float
** <tr><td> FLOAT <td> BLOB <td> Same as FLOAT->TEXT
** <tr><td> TEXT <td> INTEGER <td> Use atoi()
** <tr><td> TEXT <td> FLOAT <td> Use atof()
** <tr><td> FLOAT <td> BLOB <td> [CAST] to BLOB
** <tr><td> TEXT <td> INTEGER <td> [CAST] to INTEGER
** <tr><td> TEXT <td> FLOAT <td> [CAST] to REAL
** <tr><td> TEXT <td> BLOB <td> No change
** <tr><td> BLOB <td> INTEGER <td> Convert to TEXT then use atoi()
** <tr><td> BLOB <td> FLOAT <td> Convert to TEXT then use atof()
** <tr><td> BLOB <td> INTEGER <td> [CAST] to INTEGER
** <tr><td> BLOB <td> FLOAT <td> [CAST] to REAL
** <tr><td> BLOB <td> TEXT <td> Add a zero terminator if needed
** </table>
** </blockquote>)^
@ -3829,7 +3876,7 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
** described above, or until [sqlite3_step()] or [sqlite3_reset()] or
** [sqlite3_finalize()] is called. ^The memory space used to hold strings
** and BLOBs is freed automatically. Do <b>not</b> pass the pointers returned
** [sqlite3_column_blob()], [sqlite3_column_text()], etc. into
** from [sqlite3_column_blob()], [sqlite3_column_text()], etc. into
** [sqlite3_free()].
**
** ^(If a memory allocation error occurs during the evaluation of any
@ -3938,15 +3985,24 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
**
** ^The fourth parameter, eTextRep, specifies what
** [SQLITE_UTF8 | text encoding] this SQL function prefers for
** its parameters. Every SQL function implementation must be able to work
** with UTF-8, UTF-16le, or UTF-16be. But some implementations may be
** more efficient with one encoding than another. ^An application may
** invoke sqlite3_create_function() or sqlite3_create_function16() multiple
** times with the same function but with different values of eTextRep.
** its parameters. The application should set this parameter to
** [SQLITE_UTF16LE] if the function implementation invokes
** [sqlite3_value_text16le()] on an input, or [SQLITE_UTF16BE] if the
** implementation invokes [sqlite3_value_text16be()] on an input, or
** [SQLITE_UTF16] if [sqlite3_value_text16()] is used, or [SQLITE_UTF8]
** otherwise. ^The same SQL function may be registered multiple times using
** different preferred text encodings, with different implementations for
** each encoding.
** ^When multiple implementations of the same function are available, SQLite
** will pick the one that involves the least amount of data conversion.
** If there is only a single implementation which does not care what text
** encoding is used, then the fourth argument should be [SQLITE_ANY].
**
** ^The fourth parameter may optionally be ORed with [SQLITE_DETERMINISTIC]
** to signal that the function will always return the same result given
** the same inputs within a single SQL statement. Most SQL functions are
** deterministic. The built-in [random()] SQL function is an example of a
** function that is not deterministic. The SQLite query planner is able to
** perform additional optimizations on deterministic functions, so use
** of the [SQLITE_DETERMINISTIC] flag is recommended where possible.
**
** ^(The fifth parameter is an arbitrary pointer. The implementation of the
** function can gain access to this pointer using [sqlite3_user_data()].)^
@ -4032,9 +4088,19 @@ SQLITE_API int sqlite3_create_function_v2(
#define SQLITE_UTF16LE 2
#define SQLITE_UTF16BE 3
#define SQLITE_UTF16 4 /* Use native byte order */
#define SQLITE_ANY 5 /* sqlite3_create_function only */
#define SQLITE_ANY 5 /* Deprecated */
#define SQLITE_UTF16_ALIGNED 8 /* sqlite3_create_collation only */
/*
** CAPI3REF: Function Flags
**
** These constants may be ORed together with the
** [SQLITE_UTF8 | preferred text encoding] as the fourth argument
** to [sqlite3_create_function()], [sqlite3_create_function16()], or
** [sqlite3_create_function_v2()].
*/
#define SQLITE_DETERMINISTIC 0x800
/*
** CAPI3REF: Deprecated Functions
** DEPRECATED
@ -4806,12 +4872,13 @@ SQLITE_API void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
**
** ^The sqlite3_update_hook() interface registers a callback function
** with the [database connection] identified by the first argument
** to be invoked whenever a row is updated, inserted or deleted.
** to be invoked whenever a row is updated, inserted or deleted in
** a rowid table.
** ^Any callback set by a previous call to this function
** for the same database connection is overridden.
**
** ^The second argument is a pointer to the function to invoke when a
** row is updated, inserted or deleted.
** row is updated, inserted or deleted in a rowid table.
** ^The first argument to the callback is a copy of the third argument
** to sqlite3_update_hook().
** ^The second callback argument is one of [SQLITE_INSERT], [SQLITE_DELETE],
@ -4824,6 +4891,7 @@ SQLITE_API void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
**
** ^(The update hook is not invoked when internal system tables are
** modified (i.e. sqlite_master and sqlite_sequence).)^
** ^The update hook is not invoked when [WITHOUT ROWID] tables are modified.
**
** ^In the current implementation, the update hook
** is not invoked when duplication rows are deleted because of an
@ -4905,8 +4973,8 @@ SQLITE_API int sqlite3_release_memory(int);
**
** ^The sqlite3_db_release_memory(D) interface attempts to free as much heap
** memory as possible from database connection D. Unlike the
** [sqlite3_release_memory()] interface, this interface is effect even
** when then [SQLITE_ENABLE_MEMORY_MANAGEMENT] compile-time option is
** [sqlite3_release_memory()] interface, this interface is in effect even
** when the [SQLITE_ENABLE_MEMORY_MANAGEMENT] compile-time option is
** omitted.
**
** See also: [sqlite3_release_memory()]
@ -5281,10 +5349,22 @@ struct sqlite3_module {
** the correct order to satisfy the ORDER BY clause so that no separate
** sorting step is required.
**
** ^The estimatedCost value is an estimate of the cost of doing the
** particular lookup. A full scan of a table with N entries should have
** a cost of N. A binary search of a table of N entries should have a
** cost of approximately log(N).
** ^The estimatedCost value is an estimate of the cost of a particular
** strategy. A cost of N indicates that the cost of the strategy is similar
** to a linear scan of an SQLite table with N rows. A cost of log(N)
** indicates that the expense of the operation is similar to that of a
** binary search on a unique indexed field of an SQLite table with N rows.
**
** ^The estimatedRows value is an estimate of the number of rows that
** will be returned by the strategy.
**
** IMPORTANT: The estimatedRows field was added to the sqlite3_index_info
** structure for SQLite version 3.8.2. If a virtual table extension is
** used with an SQLite version earlier than 3.8.2, the results of attempting
** to read or write the estimatedRows field are undefined (but are likely
** to included crashing the application). The estimatedRows field should
** therefore only be used if [sqlite3_libversion_number()] returns a
** value greater than or equal to 3008002.
*/
struct sqlite3_index_info {
/* Inputs */
@ -5309,7 +5389,9 @@ struct sqlite3_index_info {
char *idxStr; /* String, possibly obtained from sqlite3_malloc */
int needToFreeIdxStr; /* Free idxStr using sqlite3_free() if true */
int orderByConsumed; /* True if output is already ordered */
double estimatedCost; /* Estimated cost of using this index */
double estimatedCost; /* Estimated cost of using this index */
/* Fields below are only available in SQLite 3.8.2 and later */
sqlite3_int64 estimatedRows; /* Estimated number of rows returned */
};
/*
@ -5513,6 +5595,9 @@ typedef struct sqlite3_blob sqlite3_blob;
** interface. Use the [UPDATE] SQL command to change the size of a
** blob.
**
** ^The [sqlite3_blob_open()] interface will fail for a [WITHOUT ROWID]
** table. Incremental BLOB I/O is not possible on [WITHOUT ROWID] tables.
**
** ^The [sqlite3_bind_zeroblob()] and [sqlite3_result_zeroblob()] interfaces
** and the built-in [zeroblob] SQL function can be used, if desired,
** to create an empty, zero-filled blob in which to read or write using
@ -6036,7 +6121,8 @@ SQLITE_API int sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_SCRATCHMALLOC 17
#define SQLITE_TESTCTRL_LOCALTIME_FAULT 18
#define SQLITE_TESTCTRL_EXPLAIN_STMT 19
#define SQLITE_TESTCTRL_LAST 19
#define SQLITE_TESTCTRL_NEVER_CORRUPT 20
#define SQLITE_TESTCTRL_LAST 20
/*
** CAPI3REF: SQLite Runtime Status

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.telegram.messenger"
android:versionCode="160"
android:versionName="1.3.21">
android:versionCode="175"
android:versionName="1.3.26">
<supports-screens android:anyDensity="true"
android:smallScreens="true"
@ -25,7 +25,7 @@
<uses-feature android:name="android.hardware.screen.PORTRAIT" android:required="false" />
<uses-permission android:name="android.permission.INTERNET" />
<!--<uses-permission android:name="android.permission.RECORD_AUDIO" />-->
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.RECEIVE_SMS" />
@ -55,7 +55,7 @@
<permission android:name="org.telegram.messenger.permission.C2D_MESSAGE" android:protectionLevel="signature" />
<application
android:allowBackup="true"
android:allowBackup="false"
android:icon="@drawable/ic_launcher"
android:label="@string/AppName"
android:theme="@style/Theme.TMessages.Start"
@ -84,11 +84,26 @@
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="video/*"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND_MULTIPLE"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="image/*"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="text/plain"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="*/*"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND_MULTIPLE"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="*/*"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
@ -165,9 +180,6 @@
<meta-data android:name="android.provider.CONTACTS_STRUCTURE"
android:resource="@xml/contacts" />
</service>
<service android:name="org.telegram.messenger.GcmService" android:enabled="true" android:exported="true"/>
<service android:name=".BackgroundService" android:enabled="true" android:stopWithTask="false"/>
<uses-library android:name="com.google.android.maps" android:required="false"/>
</application>

View File

@ -22,8 +22,6 @@ import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import jawnae.pyronet.PyroException;
public class ByteStream {
private final List<ByteBuffer> queue;
@ -51,9 +49,11 @@ public class ByteStream {
public boolean hasData() {
int size = this.queue.size();
for (int i = 0; i < size; i++)
if (this.queue.get(i).hasRemaining())
for (ByteBuffer aQueue : this.queue) {
if (aQueue.hasRemaining()) {
return true;
}
}
return false;
}
@ -61,8 +61,9 @@ public class ByteStream {
int size = this.queue.size();
int sum = 0;
for (int i = 0; i < size; i++)
sum += this.queue.get(i).remaining();
for (ByteBuffer aQueue : this.queue) {
sum += aQueue.remaining();
}
return sum;
}

View File

@ -107,6 +107,7 @@ public class PyroClient {
* set
*/
@SuppressWarnings("unchecked")
public <T> T attachment() {
return (T) this.attachment;
}
@ -155,12 +156,6 @@ public class PyroClient {
((SocketChannel) key.channel()).socket().setKeepAlive(enabled);
}
//
//
//
private boolean doEagerWrite = false;
/**
@ -320,7 +315,7 @@ public class PyroClient {
public void run() {
try {
if (key.channel().isOpen()) {
((SocketChannel) key.channel()).close();
(key.channel()).close();
}
} catch (Exception exc) {
selector().scheduleTask(this);
@ -340,7 +335,7 @@ public class PyroClient {
public boolean isDisconnected() {
this.selector.checkThread();
return !((SocketChannel) this.key.channel()).isOpen();
return !this.key.channel().isOpen();
}
//
@ -368,9 +363,7 @@ public class PyroClient {
private long lastEventTime;
boolean didTimeout(long now) {
if (this.timeout == 0)
return false; // never timeout
return (now - this.lastEventTime) > this.timeout;
return this.timeout != 0 && (now - this.lastEventTime) > this.timeout;
}
private void onReadyToConnect(long now) throws IOException {
@ -442,7 +435,7 @@ public class PyroClient {
try {
// if the key is invalid, the channel may remain open!!
((SocketChannel) this.key.channel()).close();
this.key.channel().close();
} catch (Exception exc) {
// type: java.io.IOException
// message:
@ -488,7 +481,7 @@ public class PyroClient {
+ "]";
}
private final String getAddressText() {
private String getAddressText() {
if (!this.key.channel().isOpen())
return "closed";
@ -510,7 +503,7 @@ public class PyroClient {
interested);
}
static final SelectionKey bindAndConfigure(PyroSelector selector,
static SelectionKey bindAndConfigure(PyroSelector selector,
SocketChannel channel, InetSocketAddress bind) throws IOException {
selector.checkThread();
@ -519,7 +512,7 @@ public class PyroClient {
return configure(selector, channel, true);
}
static final SelectionKey configure(PyroSelector selector,
static SelectionKey configure(PyroSelector selector,
SocketChannel channel, boolean connect) throws IOException {
selector.checkThread();

View File

@ -18,6 +18,9 @@
package jawnae.pyronet;
import org.telegram.messenger.ConnectionsManager;
import org.telegram.messenger.FileLog;
import java.io.IOException;
import java.nio.ByteBuffer;
@ -27,13 +30,16 @@ public class PyroClientAdapter implements PyroClientListener {
}
public void unconnectableClient(PyroClient client, Exception cause) {
System.out.println("unconnectable");
if (ConnectionsManager.DEBUG_VERSION) {
FileLog.e("tmessages", "unconnectable");
}
}
public void droppedClient(PyroClient client, IOException cause) {
if (cause != null) {
System.out.println(this.getClass().getSimpleName()
+ ".droppedClient() caught exception: " + cause);
if (ConnectionsManager.DEBUG_VERSION) {
FileLog.e("tmessages", this.getClass().getSimpleName() + ".droppedClient() caught exception: " + cause);
}
}
}

View File

@ -21,8 +21,6 @@ package jawnae.pyronet;
import java.io.IOException;
import java.nio.ByteBuffer;
import jawnae.pyronet.PyroClient;
public interface PyroClientListener {
public void connectedClient(PyroClient client);

View File

@ -75,14 +75,8 @@ public class PyroSelector {
return copy;
}
//
public final boolean isNetworkThread() {
if (DO_NOT_CHECK_NETWORK_THREAD) {
return true;
}
return networkThread == Thread.currentThread();
return DO_NOT_CHECK_NETWORK_THREAD || networkThread == Thread.currentThread();
}
public final Thread networkThread() {
@ -95,8 +89,7 @@ public class PyroSelector {
}
if (!this.isNetworkThread()) {
throw new PyroException(
"call from outside the network-thread, you must schedule tasks");
throw new PyroException("call from outside the network-thread, you must schedule tasks");
}
}
@ -104,13 +97,8 @@ public class PyroSelector {
return this.connect(host, null);
}
public PyroClient connect(InetSocketAddress host, InetSocketAddress bind)
throws IOException {
try {
return new PyroClient(this, bind, host);
} catch (IOException exc) {
throw exc;
}
public PyroClient connect(InetSocketAddress host, InetSocketAddress bind) throws IOException {
return new PyroClient(this, bind, host);
}
public void select() {
@ -144,17 +132,16 @@ public class PyroSelector {
}
}
private final void performNioSelect(long timeout) {
private void performNioSelect(long timeout) {
int selected;
try {
selected = nioSelector.select(timeout);
} catch (IOException exc) {
exc.printStackTrace();
return;
}
}
private final void handleSelectedKeys(long now) {
private void handleSelectedKeys(long now) {
Iterator<SelectionKey> keys = nioSelector.selectedKeys().iterator();
while (keys.hasNext()) {
@ -168,7 +155,7 @@ public class PyroSelector {
}
}
private final void handleSocketTimeouts(long now) {
private void handleSocketTimeouts(long now) {
for (SelectionKey key: nioSelector.keys()) {
if (key.channel() instanceof SocketChannel) {
PyroClient client = (PyroClient) key.attachment();

View File

@ -58,9 +58,12 @@ public class PhoneFormat {
return res.toString();
}
public static String stripExceptNumbers(String str) {
public static String stripExceptNumbers(String str, boolean includePlus) {
StringBuilder res = new StringBuilder(str);
String phoneChars = "0123456789";
if (includePlus) {
phoneChars += "+";
}
for (int i = res.length() - 1; i >= 0; i--) {
if (!phoneChars.contains(res.substring(i, i + 1))) {
res.deleteCharAt(i);
@ -69,6 +72,10 @@ public class PhoneFormat {
return res.toString();
}
public static String stripExceptNumbers(String str) {
return stripExceptNumbers(str, false);
}
public PhoneFormat() {
init(null);
}

View File

@ -0,0 +1,35 @@
/*
* This is the source code of Telegram for Android v. 1.3.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
*
* Copyright Nikolai Kudashov, 2013-2014.
*/
package org.telegram.messenger;
public abstract class AbsSerializedData {
public abstract void writeInt32(int x);
public abstract void writeInt64(long x);
public abstract void writeBool(boolean value);
public abstract void writeRaw(byte[] b);
public abstract void writeRaw(byte[] b, int offset, int count);
public abstract void writeByte(int i);
public abstract void writeByte(byte b);
public abstract void writeString(String s);
public abstract void writeByteArray(byte[] b, int offset, int count);
public abstract void writeByteArray(byte[] b);
public abstract void writeDouble(double d);
public abstract int readInt32();
public abstract int readInt32(boolean[] error);
public abstract boolean readBool();
public abstract long readInt64();
public abstract long readInt64(boolean[] error);
public abstract void readRaw(byte[] b);
public abstract byte[] readData(int count);
public abstract String readString();
public abstract byte[] readByteArray();
public abstract ByteBufferDesc readByteBuffer();
public abstract double readDouble();
public abstract int length();
}

View File

@ -1,61 +0,0 @@
/*
* This is the source code of Telegram for Android v. 1.3.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
*
* Copyright Nikolai Kudashov, 2013.
*/
package org.telegram.messenger;
import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.util.Log;
public class BackgroundService extends Service {
private Handler handler = new Handler(Looper.getMainLooper());
private Runnable checkRunnable = new Runnable() {
@Override
public void run() {
check();
}
};
public BackgroundService() {
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
check();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
Log.e("tmessages", "onStartCommand");
return START_STICKY;
}
private void check() {
handler.removeCallbacks(checkRunnable);
handler.postDelayed(checkRunnable, 1500);
ConnectionsManager connectionsManager = ConnectionsManager.Instance;
}
@Override
public void onDestroy() {
super.onDestroy();
Log.e("tmessages", "onDestroy");
}
}

View File

@ -0,0 +1,136 @@
/*
* This is the source code of Telegram for Android v. 1.3.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
*
* Copyright Nikolai Kudashov, 2013-2014.
*/
package org.telegram.messenger;
import java.util.concurrent.ConcurrentLinkedQueue;
public class BuffersStorage {
public static BuffersStorage Instance = new BuffersStorage();
private final ConcurrentLinkedQueue<ByteBufferDesc> freeBuffers128;
private final ConcurrentLinkedQueue<ByteBufferDesc> freeBuffers1024;
private final ConcurrentLinkedQueue<ByteBufferDesc> freeBuffers4096;
private final ConcurrentLinkedQueue<ByteBufferDesc> freeBuffers16384;
private final ConcurrentLinkedQueue<ByteBufferDesc> freeBuffers32768;
public BuffersStorage() {
freeBuffers128 = new ConcurrentLinkedQueue<ByteBufferDesc>();
freeBuffers1024 = new ConcurrentLinkedQueue<ByteBufferDesc>();
freeBuffers4096 = new ConcurrentLinkedQueue<ByteBufferDesc>();
freeBuffers16384 = new ConcurrentLinkedQueue<ByteBufferDesc>();
freeBuffers32768 = new ConcurrentLinkedQueue<ByteBufferDesc>();
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) {
ByteBufferDesc buffer = null;
if (size <= 128) {
synchronized (freeBuffers128) {
buffer = freeBuffers128.poll();
}
if (buffer == null) {
buffer = new ByteBufferDesc(128);
FileLog.e("tmessages", "create new 128 buffer");
}
} else if (size <= 1024 + 200) {
synchronized (freeBuffers1024) {
buffer = freeBuffers1024.poll();
}
if (buffer == null) {
buffer = new ByteBufferDesc(1024 + 200);
FileLog.e("tmessages", "create new 1024 buffer");
}
} else if (size <= 4096 + 200) {
synchronized (freeBuffers4096) {
buffer = freeBuffers4096.poll();
}
if (buffer == null) {
buffer = new ByteBufferDesc(4096 + 200);
FileLog.e("tmessages", "create new 4096 buffer");
}
} else if (size <= 16384 + 200) {
synchronized (freeBuffers16384) {
buffer = freeBuffers16384.poll();
}
if (buffer == null) {
buffer = new ByteBufferDesc(16384 + 200);
FileLog.e("tmessages", "create new 16384 buffer");
}
} else if (size <= 40000) {
synchronized (freeBuffers32768) {
buffer = freeBuffers32768.poll();
}
if (buffer == null) {
buffer = new ByteBufferDesc(40000);
FileLog.e("tmessages", "create new 40000 buffer");
}
} else {
buffer = new ByteBufferDesc(size);
}
buffer.buffer.limit(size).rewind();
return buffer;
}
public void reuseFreeBuffer(ByteBufferDesc buffer) {
if (buffer == null) {
return;
}
if (buffer.buffer.capacity() == 128) {
synchronized (freeBuffers128) {
if (freeBuffers128.contains(buffer)) {
throw new RuntimeException("already containing buffer! 0");
}
freeBuffers128.add(buffer);
}
} else if (buffer.buffer.capacity() == 1024 + 200) {
synchronized (freeBuffers1024) {
if (freeBuffers1024.contains(buffer)) {
throw new RuntimeException("already containing buffer! 1");
}
freeBuffers1024.add(buffer);
}
} else if (buffer.buffer.capacity() == 4096 + 200) {
synchronized (freeBuffers4096) {
if (freeBuffers4096.contains(buffer)) {
throw new RuntimeException("already containing buffer! 2");
}
freeBuffers4096.add(buffer);
}
} else if (buffer.buffer.capacity() == 16384 + 200) {
synchronized (freeBuffers16384) {
if (freeBuffers16384.contains(buffer)) {
throw new RuntimeException("already containing buffer! 3");
}
freeBuffers16384.add(buffer);
}
} else if (buffer.buffer.capacity() == 40000) {
synchronized (freeBuffers32768) {
if (freeBuffers32768.contains(buffer)) {
throw new RuntimeException("already containing buffer! 4");
}
freeBuffers32768.add(buffer);
}
}
}
}

View File

@ -0,0 +1,384 @@
/*
* This is the source code of Telegram for Android v. 1.3.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
*
* Copyright Nikolai Kudashov, 2013-2014.
*/
package org.telegram.messenger;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
public class ByteBufferDesc extends AbsSerializedData {
public ByteBuffer buffer;
private boolean justCalc = false;
private int len = 0;
public ByteBufferDesc(int size) {
buffer = ByteBuffer.allocateDirect(size);
buffer.order(ByteOrder.LITTLE_ENDIAN);
}
public ByteBufferDesc(boolean calculate) {
justCalc = calculate;
}
public int position() {
return buffer.position();
}
public void position(int position) {
buffer.position(position);
}
public int capacity() {
return buffer.capacity();
}
public int limit() {
return buffer.limit();
}
public void limit(int limit) {
buffer.limit(limit);
}
public void put(ByteBuffer buff) {
buffer.put(buff);
}
public void rewind() {
buffer.rewind();
}
public void compact() {
buffer.compact();
}
public boolean hasRemaining() {
return buffer.hasRemaining();
}
public void writeInt32(int x) {
try {
if (!justCalc) {
buffer.putInt(x);
} else {
len += 4;
}
} catch(Exception e) {
FileLog.e("tmessages", "write int32 error");
}
}
public void writeInt64(long x) {
try {
if (!justCalc) {
buffer.putLong(x);
} else {
len += 4;
}
} catch(Exception e) {
FileLog.e("tmessages", "write int64 error");
}
}
public void writeBool(boolean value) {
if (!justCalc) {
if (value) {
writeInt32(0x997275b5);
} else {
writeInt32(0xbc799737);
}
} else {
len += 4;
}
}
public void writeRaw(byte[] b) {
try {
if (!justCalc) {
buffer.put(b);
} else {
len += b.length;
}
} catch (Exception x) {
FileLog.e("tmessages", "write raw error");
}
}
public void writeRaw(byte[] b, int offset, int count) {
try {
if (!justCalc) {
buffer.put(b, offset, count);
} else {
len += count;
}
} catch (Exception x) {
FileLog.e("tmessages", "write raw error");
}
}
public void writeByte(int i) {
writeByte((byte)i);
}
public void writeByte(byte b) {
try {
if (!justCalc) {
buffer.put(b);
} else {
len += 1;
}
} catch (Exception e) {
FileLog.e("tmessages", "write byte error");
}
}
public void writeString(String s) {
try {
writeByteArray(s.getBytes("UTF-8"));
} catch(Exception x) {
FileLog.e("tmessages", "write string error");
}
}
public void writeByteArray(byte[] b, int offset, int count) {
try {
if(count <= 253) {
if (!justCalc) {
buffer.put((byte)count);
} else {
len += 1;
}
} else {
if (!justCalc) {
buffer.put((byte)254);
buffer.put((byte)count);
buffer.put((byte)(count >> 8));
buffer.put((byte)(count >> 16));
} else {
len += 4;
}
}
if (!justCalc) {
buffer.put(b, offset, count);
} else {
len += count;
}
int i = count <= 253 ? 1 : 4;
while ((count + i) % 4 != 0) {
if (!justCalc) {
buffer.put((byte)0);
} else {
len += 1;
}
i++;
}
} catch (Exception x) {
FileLog.e("tmessages", "write byte array error");
}
}
public void writeByteArray(byte[] b) {
try {
if (b.length <= 253) {
if (!justCalc) {
buffer.put((byte) b.length);
} else {
len += 1;
}
} else {
if (!justCalc) {
buffer.put((byte) 254);
buffer.put((byte) b.length);
buffer.put((byte) (b.length >> 8));
buffer.put((byte) (b.length >> 16));
} else {
len += 4;
}
}
if (!justCalc) {
buffer.put(b);
} else {
len += b.length;
}
int i = b.length <= 253 ? 1 : 4;
while((b.length + i) % 4 != 0) {
if (!justCalc) {
buffer.put((byte) 0);
} else {
len += 1;
}
i++;
}
} catch (Exception x) {
FileLog.e("tmessages", "write byte array error");
}
}
public void writeDouble(double d) {
try {
writeInt64(Double.doubleToRawLongBits(d));
} catch(Exception x) {
FileLog.e("tmessages", "write double error");
}
}
public int readInt32() {
return readInt32(null);
}
public int readInt32(boolean[] error) {
try {
int i = buffer.getInt();
if (error != null) {
error[0] = false;
}
return i;
} catch (Exception x) {
if (error != null) {
error[0] = true;
}
FileLog.e("tmessages", "read int32 error");
}
return 0;
}
public boolean readBool() {
int consructor = readInt32();
if (consructor == 0x997275b5) {
return true;
} else if (consructor == 0xbc799737) {
return false;
}
FileLog.e("tmessages", "Not bool value!");
return false;
}
public long readInt64() {
return readInt64(null);
}
public long readInt64(boolean[] error) {
try {
long i = buffer.getLong();
if (error != null) {
error[0] = false;
}
return i;
} catch (Exception x) {
if (error != null) {
error[0] = true;
}
FileLog.e("tmessages", "read int64 error");
}
return 0;
}
public void readRaw(byte[] b) {
try {
buffer.get(b);
} catch (Exception x) {
FileLog.e("tmessages", "read raw error");
}
}
public byte[] readData(int count) {
byte[] arr = new byte[count];
readRaw(arr);
return arr;
}
public String readString() {
try {
int sl = 1;
int l = getIntFromByte(buffer.get());
if(l >= 254) {
l = getIntFromByte(buffer.get()) | (getIntFromByte(buffer.get()) << 8) | (getIntFromByte(buffer.get()) << 16);
sl = 4;
}
byte[] b = new byte[l];
buffer.get(b);
int i = sl;
while((l + i) % 4 != 0) {
buffer.get();
i++;
}
return new String(b, "UTF-8");
} catch (Exception x) {
FileLog.e("tmessages", "read string error");
}
return null;
}
public int getIntFromByte(byte b) {
return b >= 0 ? b : ((int)b) + 256;
}
public byte[] readByteArray() {
try {
int sl = 1;
int l = getIntFromByte(buffer.get());
if (l >= 254) {
l = getIntFromByte(buffer.get()) | (getIntFromByte(buffer.get()) << 8) | (getIntFromByte(buffer.get()) << 16);
sl = 4;
}
byte[] b = new byte[l];
buffer.get(b);
int i = sl;
while((l + i) % 4 != 0) {
buffer.get();
i++;
}
return b;
} catch (Exception x) {
FileLog.e("tmessages", "read byte array error");
}
return null;
}
public ByteBufferDesc readByteBuffer() {
try {
int sl = 1;
int l = getIntFromByte(buffer.get());
if (l >= 254) {
l = getIntFromByte(buffer.get()) | (getIntFromByte(buffer.get()) << 8) | (getIntFromByte(buffer.get()) << 16);
sl = 4;
}
ByteBufferDesc b = BuffersStorage.Instance.getFreeBuffer(l);
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();
i++;
}
return b;
} catch (Exception x) {
FileLog.e("tmessages", "read byte array error");
}
return null;
}
public double readDouble() {
try {
return Double.longBitsToDouble(readInt64());
} catch(Exception x) {
FileLog.e("tmessages", "read double error");
}
return 0;
}
public int length() {
if (!justCalc) {
return buffer.position();
}
return len;
}
}

View File

@ -16,9 +16,6 @@ import android.net.NetworkInfo;
import android.os.Build;
import android.util.Base64;
import org.telegram.TL.TLClassStore;
import org.telegram.TL.TLObject;
import org.telegram.TL.TLRPC;
import org.telegram.ui.ApplicationLoader;
import java.io.File;
@ -37,7 +34,7 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection.
public static int APP_ID = 2458;
public static String APP_HASH = "5bce48dc7d331e62c955669eb7233217";
public static String HOCKEY_APP_HASH = "your-hockeyapp-api-key-here";
public static boolean disableContactsImport = false;
public static String GCM_SENDER_ID = "760348033672";
private HashMap<Integer, Datacenter> datacenters = new HashMap<Integer, Datacenter>();
private HashMap<Long, ArrayList<Long>> processedMessageIdsSet = new HashMap<Long, ArrayList<Long>>();
@ -67,7 +64,7 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection.
public int timeDifference = 0;
public int currentPingTime;
private int lastDestroySessionRequestTime;
private final boolean isDebugSession = false;
public static final boolean isDebugSession = false;
private boolean updatingDcSettings = false;
private int updatingDcStartTime = 0;
private int lastDcUpdateTime = 0;
@ -693,7 +690,7 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection.
}
object = invoke;
}
TLRPC.invokeWithLayer11 invoke = new TLRPC.invokeWithLayer11();
TLRPC.invokeWithLayer12 invoke = new TLRPC.invokeWithLayer12();
invoke.query = object;
FileLog.d("wrap in layer", "" + object);
return invoke;
@ -949,6 +946,9 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection.
Datacenter requestDatacenter = datacenterWithId(datacenterId);
if (!request.initRequest && requestDatacenter.lastInitVersion != currentAppVersion) {
request.rpcRequest = wrapInLayer(request.rawRequest, requestDatacenter.datacenterId, request);
SerializedData os = new SerializedData(true);
request.rpcRequest.serializeToStream(os);
request.serializedLength = os.length();
}
if (requestDatacenter == null) {
@ -1182,9 +1182,6 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection.
Integer tokenIt = activeTransportTokens.get(requestDatacenter.datacenterId);
request.transportChannelToken = tokenIt != null ? tokenIt : 0;
} else if ((request.flags & RPCRequest.RPCRequestClassUploadMedia) != 0) {
if (uploadRunningRequestCount >= 20)
continue;
if (!haveNetwork) {
FileLog.d("tmessages", "Don't have any network connection, skipping upload request");
continue;
@ -1573,12 +1570,12 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection.
TLRPC.TL_protoMessage message = networkMessage.protoMessage;
if (DEBUG_VERSION) {
if (message.body instanceof TLRPC.invokeWithLayer11) {
FileLog.d("tmessages", sessionId + ":DC" + datacenter.datacenterId + "> Send message (" + message.seqno + ", " + message.msg_id + "): " + ((TLRPC.invokeWithLayer11)message.body).query);
if (message.body instanceof TLRPC.invokeWithLayer12) {
FileLog.d("tmessages", sessionId + ":DC" + datacenter.datacenterId + "> Send message (" + message.seqno + ", " + message.msg_id + "): " + ((TLRPC.invokeWithLayer12)message.body).query);
} else if (message.body instanceof TLRPC.initConnection) {
TLRPC.initConnection r = (TLRPC.initConnection)message.body;
if (r.query instanceof TLRPC.invokeWithLayer11) {
FileLog.d("tmessages", sessionId + ":DC" + datacenter.datacenterId + "> Send message (" + message.seqno + ", " + message.msg_id + "): " + ((TLRPC.invokeWithLayer11)r.query).query);
if (r.query instanceof TLRPC.invokeWithLayer12) {
FileLog.d("tmessages", sessionId + ":DC" + datacenter.datacenterId + "> Send message (" + message.seqno + ", " + message.msg_id + "): " + ((TLRPC.invokeWithLayer12)r.query).query);
} else {
FileLog.d("tmessages", sessionId + ":DC" + datacenter.datacenterId + "> Send message (" + message.seqno + ", " + message.msg_id + "): " + r.query);
}
@ -1613,12 +1610,12 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection.
TLRPC.TL_protoMessage message = networkMessage.protoMessage;
containerMessages.add(message);
if (DEBUG_VERSION) {
if (message.body instanceof TLRPC.invokeWithLayer11) {
FileLog.d("tmessages", sessionId + ":DC" + datacenter.datacenterId + "> Send message (" + message.seqno + ", " + message.msg_id + "): " + ((TLRPC.invokeWithLayer11)message.body).query);
if (message.body instanceof TLRPC.invokeWithLayer12) {
FileLog.d("tmessages", sessionId + ":DC" + datacenter.datacenterId + "> Send message (" + message.seqno + ", " + message.msg_id + "): " + ((TLRPC.invokeWithLayer12)message.body).query);
} else if (message.body instanceof TLRPC.initConnection) {
TLRPC.initConnection r = (TLRPC.initConnection)message.body;
if (r.query instanceof TLRPC.invokeWithLayer11) {
FileLog.d("tmessages", sessionId + ":DC" + datacenter.datacenterId + "> Send message (" + message.seqno + ", " + message.msg_id + "): " + ((TLRPC.invokeWithLayer11)r.query).query);
if (r.query instanceof TLRPC.invokeWithLayer12) {
FileLog.d("tmessages", sessionId + ":DC" + datacenter.datacenterId + "> Send message (" + message.seqno + ", " + message.msg_id + "): " + ((TLRPC.invokeWithLayer12)r.query).query);
} else {
FileLog.d("tmessages", sessionId + ":DC" + datacenter.datacenterId + "> Send message (" + message.seqno + ", " + message.msg_id + "): " + r.query);
}
@ -1672,11 +1669,11 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection.
dataForEncryption.writeByte(b[0]);
}
byte[] encryptedData = Utilities.aesIgeEncryption(dataForEncryption.toByteArray(), keyData.aesKey, keyData.aesIv, true, false);
byte[] encryptedData = Utilities.aesIgeEncryption(dataForEncryption.toByteArray(), keyData.aesKey, keyData.aesIv, true, false, 0);
try {
SerializedData data = new SerializedData(datacenter.authKeyId.length + messageKey.length + encryptedData.length);
data.writeRaw(datacenter.authKeyId);
SerializedData data = new SerializedData(8 + messageKey.length + encryptedData.length);
data.writeInt64(datacenter.authKeyId);
data.writeRaw(messageKey);
data.writeRaw(encryptedData);
@ -1687,7 +1684,7 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection.
messageData = null;
System.gc();
SerializedData data = new SerializedData();
data.writeRaw(datacenter.authKeyId);
data.writeInt64(datacenter.authKeyId);
data.writeRaw(messageKey);
data.writeRaw(encryptedData);
@ -1859,6 +1856,8 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection.
request.completionBlock.run(futureSalts, null);
}
futureSalts.freeResources();
messagesConfirmed(requestMid);
rpcCompleted(requestMid);
@ -2072,6 +2071,8 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection.
}
}
resultContainer.freeResources();
if (!found) {
FileLog.d("tmessages", "Response received, but request wasn't found.");
rpcCompleted(resultMid);
@ -2198,8 +2199,9 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection.
return null;
}
TLRPC.TL_ping ping = new TLRPC.TL_ping();
TLRPC.TL_ping_delay_disconnect ping = new TLRPC.TL_ping_delay_disconnect();
ping.ping_id = nextPingId++;
ping.disconnect_delay = 35;
if (recordTime && sessionId == datacenter.authSessionId) {
pingIdToDate.put(ping.ping_id, (int)(System.currentTimeMillis() / 1000));
@ -2234,10 +2236,11 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection.
byte[] keyId = is.readData(8);
SerializedData keyIdData = new SerializedData(keyId);
if (keyIdData.readInt64() == 0) {
long key = keyIdData.readInt64();
if (key == 0) {
return -1;
} else {
if (datacenter.authKeyId == null || !Arrays.equals(keyId, datacenter.authKeyId)) {
if (datacenter.authKeyId == 0 || key != datacenter.authKeyId) {
FileLog.e("tmessages", "Error: invalid auth key id " + connection);
return -1;
}
@ -2246,7 +2249,7 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection.
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);
messageData = Utilities.aesIgeEncryption(messageData, keyData.aesKey, keyData.aesIv, false, false, 0);
if (messageData == null) {
return -1;
@ -2441,7 +2444,7 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection.
}
@Override
public void tcpConnectionReceivedData(TcpConnection connection, byte[] data) {
public void tcpConnectionReceivedData(TcpConnection connection, ByteBufferDesc data, int length) {
if (connection.getDatacenterId() == currentDatacenterId && (connection.transportRequestClass & RPCRequest.RPCRequestClassGeneric) != 0) {
if (connectionState == 1 || connectionState == 2) {
connectionState = 3;
@ -2456,22 +2459,18 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection.
}
Datacenter datacenter = datacenterWithId(connection.getDatacenterId());
SerializedData is = new SerializedData(data);
byte[] keyId = is.readData(8);
SerializedData keyIdData = new SerializedData(keyId);
if (keyIdData.readInt64() == 0) {
long messageId = is.readInt64();
long keyId = data.readInt64();
if (keyId == 0) {
long messageId = data.readInt64();
if (isMessageIdProcessed(0, messageId)) {
finishUpdatingState(connection);
return;
}
int messageLength = is.readInt32();
int messageLength = data.readInt32();
int constructor = data.readInt32();
int constructor = is.readInt32();
TLObject object = TLClassStore.Instance().TLdeserialize(is, constructor, getRequestWithMessageId(messageId));
TLObject object = TLClassStore.Instance().TLdeserialize(data, constructor, getRequestWithMessageId(messageId));
processMessage(object, messageId, 0, 0, connection, 0, 0, 0);
@ -2479,29 +2478,29 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection.
addProcessedMessageId(0, messageId);
}
} else {
if (datacenter.authKeyId == null || !Arrays.equals(keyId, datacenter.authKeyId)) {
if (datacenter.authKeyId == 0 || keyId != datacenter.authKeyId) {
FileLog.e("tmessages", "Error: invalid auth key id " + connection);
connection.suspendConnection(true);
connection.connect();
return;
}
byte[] messageKey = is.readData(16);
byte[] messageKey = data.readData(16);
MessageKeyData keyData = Utilities.generateMessageKeyData(datacenter.authKey, messageKey, true);
data.compact();
data.limit(data.position());
data.position(0);
byte[] messageData = is.readData(data.length - 24);
Utilities.aesIgeEncryption2(data.buffer, keyData.aesKey, keyData.aesIv, false, false, length - 24);
// if (messageData == null) {
// FileLog.e("tmessages", "Error: can't decrypt message data " + connection);
// connection.suspendConnection(true);
// connection.connect();
// return;
// }
messageData = Utilities.aesIgeEncryption(messageData, keyData.aesKey, keyData.aesIv, false, false);
if (messageData == null) {
FileLog.e("tmessages", "Error: can't decrypt message data " + connection);
connection.suspendConnection(true);
connection.connect();
return;
}
SerializedData messageIs = new SerializedData(messageData);
long messageServerSalt = messageIs.readInt64();
long messageSessionId = messageIs.readInt64();
long messageServerSalt = data.readInt64();
long messageSessionId = data.readInt64();
if (messageSessionId != datacenter.authSessionId && messageSessionId != datacenter.authDownloadSessionId && messageSessionId != datacenter.authUploadSessionId) {
FileLog.e("tmessages", String.format("***** Error: invalid message session ID (%d instead of %d)", messageSessionId, datacenter.authSessionId));
@ -2511,9 +2510,9 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection.
boolean doNotProcess = false;
long messageId = messageIs.readInt64();
int messageSeqNo = messageIs.readInt32();
int messageLength = messageIs.readInt32();
long messageId = data.readInt64();
int messageSeqNo = data.readInt32();
int messageLength = data.readInt32();
if (isMessageIdProcessed(messageSessionId, messageId)) {
doNotProcess = true;
@ -2528,7 +2527,7 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection.
set.add(messageId);
}
byte[] realMessageKeyFull = Utilities.computeSHA1(messageData, 0, Math.min(messageLength + 32, messageData.length));
byte[] realMessageKeyFull = Utilities.computeSHA1(data.buffer, 0, Math.min(messageLength + 32, data.limit()));
if (realMessageKeyFull == null) {
return;
}
@ -2543,8 +2542,8 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection.
}
if (!doNotProcess) {
int constructor = messageIs.readInt32();
TLObject message = TLClassStore.Instance().TLdeserialize(messageIs, constructor, getRequestWithMessageId(messageId));
int constructor = data.readInt32();
TLObject message = TLClassStore.Instance().TLdeserialize(data, constructor, getRequestWithMessageId(messageId));
if (message == null) {
FileLog.e("tmessages", "***** Error parsing message: " + constructor);

View File

@ -11,7 +11,6 @@ package org.telegram.messenger;
import android.content.Context;
import android.content.SharedPreferences;
import org.telegram.TL.TLRPC;
import org.telegram.ui.ApplicationLoader;
import java.util.ArrayList;
@ -20,7 +19,7 @@ import java.util.Comparator;
import java.util.HashMap;
public class Datacenter {
private final int DATA_VERSION = 3;
private static final int DATA_VERSION = 4;
public int datacenterId;
public ArrayList<String> addresses = new ArrayList<String>();
@ -31,7 +30,7 @@ public class Datacenter {
public long authDownloadSessionId;
public long authUploadSessionId;
public byte[] authKey;
public byte[] authKeyId;
public long authKeyId;
public int lastInitVersion = 0;
private volatile int currentPortNum = 0;
private volatile int currentAddressNum = 0;
@ -59,7 +58,7 @@ public class Datacenter {
}
len = data.readInt32();
if (len != 0) {
authKeyId = data.readData(len);
authKeyId = data.readInt64();
}
authorized = data.readInt32() != 0;
len = data.readInt32();
@ -75,9 +74,9 @@ public class Datacenter {
}
} else if (version == 1) {
int currentVersion = data.readInt32();
if (currentVersion == 2 || currentVersion == 3) {
if (currentVersion == 2 || currentVersion == 3 || currentVersion == 4) {
datacenterId = data.readInt32();
if (currentVersion == 3) {
if (currentVersion >= 3) {
lastInitVersion = data.readInt32();
}
int len = data.readInt32();
@ -91,9 +90,13 @@ public class Datacenter {
if (len != 0) {
authKey = data.readData(len);
}
len = data.readInt32();
if (len != 0) {
authKeyId = data.readData(len);
if (currentVersion == 4) {
authKeyId = data.readInt64();
} else {
len = data.readInt32();
if (len != 0) {
authKeyId = data.readInt64();
}
}
authorized = data.readInt32() != 0;
len = data.readInt32();
@ -108,6 +111,8 @@ public class Datacenter {
authServerSaltSet.add(salt);
}
}
} else if (version == 2) {
}
readCurrentAddressAndPortNum();
}
@ -198,12 +203,7 @@ public class Datacenter {
} else {
stream.writeInt32(0);
}
if (authKeyId != null) {
stream.writeInt32(authKeyId.length);
stream.writeRaw(authKeyId);
} else {
stream.writeInt32(0);
}
stream.writeInt64(authKeyId);
stream.writeInt32(authorized ? 1 : 0);
stream.writeInt32(authServerSaltSet.size());
for (ServerSalt salt : authServerSaltSet) {
@ -215,7 +215,7 @@ public class Datacenter {
public void clear() {
authKey = null;
authKeyId = null;
authKeyId = 0;
authorized = false;
authServerSaltSet.clear();
}

View File

@ -8,9 +8,6 @@
package org.telegram.messenger;
import org.telegram.TL.TLObject;
import org.telegram.TL.TLRPC;
import java.util.HashMap;
public class ExportAuthorizationAction extends Action {

View File

@ -12,15 +12,13 @@ import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Build;
import org.telegram.TL.TLObject;
import org.telegram.TL.TLRPC;
import java.io.RandomAccessFile;
import java.net.URL;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.net.URLConnection;
import java.nio.channels.FileChannel;
import java.util.Scanner;
public class FileLoadOperation {
@ -238,14 +236,18 @@ public class FileLoadOperation {
opts.inSampleSize = (int)scaleFactor;
}
opts.inPreferredConfig = Bitmap.Config.ARGB_8888;
if (filter == null) {
opts.inPreferredConfig = Bitmap.Config.ARGB_8888;
} else {
opts.inPreferredConfig = Bitmap.Config.RGB_565;
}
opts.inDither = false;
image = BitmapFactory.decodeStream(is, null, opts);
is.close();
if (image == null) {
//if (!dontDelete) {
// cacheFileFinal.delete();
//}
if (!dontDelete && cacheFileFinal.length() == 0) {
cacheFileFinal.delete();
}
} else {
if (filter != null && image != null) {
float bitmapW = image.getWidth();
@ -278,9 +280,9 @@ public class FileLoadOperation {
}
});
} catch (Exception e) {
//if (!dontDelete) {
// cacheFileFinal.delete();
//}
if (!dontDelete && cacheFileFinal.length() == 0) {
cacheFileFinal.delete();
}
FileLog.e("tmessages", e);
}
}
@ -436,7 +438,12 @@ public class FileLoadOperation {
opts.inSampleSize = (int) scaleFactor;
}
opts.inPreferredConfig = Bitmap.Config.ARGB_8888;
if (filter == null) {
opts.inPreferredConfig = Bitmap.Config.ARGB_8888;
} else {
opts.inPreferredConfig = Bitmap.Config.RGB_565;
}
opts.inDither = false;
try {
if (renamed) {
@ -558,13 +565,13 @@ public class FileLoadOperation {
}
TLRPC.TL_upload_getFile req = new TLRPC.TL_upload_getFile();
req.location = location;
if (totalBytesCount == -1) {
req.offset = 0;
req.limit = 0;
} else {
//if (totalBytesCount == -1) {
// req.offset = 0;
// req.limit = 0;
//} else {
req.offset = downloadedBytes;
req.limit = downloadChunkSize;
}
//}
requestToken = ConnectionsManager.Instance.performRpc(req, new RPCRequest.RPCRequestDelegate() {
@Override
public void run(TLObject response, TLRPC.TL_error error) {
@ -572,22 +579,22 @@ public class FileLoadOperation {
if (error == null) {
TLRPC.TL_upload_file res = (TLRPC.TL_upload_file)response;
try {
if (res.bytes.length == 0) {
if (res.bytes.limit() == 0) {
onFinishLoadingFile();
return;
}
if (key != null) {
res.bytes = Utilities.aesIgeEncryption(res.bytes, key, iv, false, true);
Utilities.aesIgeEncryption2(res.bytes.buffer, key, iv, false, true, res.bytes.limit());
}
if (fileOutputStream != null) {
fileOutputStream.write(res.bytes);
FileChannel channel = fileOutputStream.getChannel();
channel.write(res.bytes.buffer);
}
if (fiv != null) {
fiv.seek(0);
fiv.write(iv);
}
downloadedBytes += res.bytes.length;
res.bytes = null;
downloadedBytes += res.bytes.limit();
if (totalBytesCount > 0) {
delegate.didChangedLoadProgress(FileLoadOperation.this, Math.min(1.0f, (float)downloadedBytes / (float)totalBytesCount));
}

View File

@ -16,7 +16,6 @@ import android.graphics.Matrix;
import android.media.ExifInterface;
import android.os.Build;
import org.telegram.TL.TLRPC;
import org.telegram.objects.MessageObject;
import org.telegram.ui.ApplicationLoader;
import org.telegram.ui.Views.BackupImageView;
@ -45,6 +44,7 @@ public class FileLoader {
private final int maxConcurentLoadingOpertaionsCount = 2;
private Queue<FileUploadOperation> uploadOperationQueue;
private ConcurrentHashMap<String, FileUploadOperation> uploadOperationPaths;
private ConcurrentHashMap<String, FileUploadOperation> uploadOperationPathsEnc;
private int currentUploadOperationsCount = 0;
private Queue<FileLoadOperation> loadOperationQueue;
private ConcurrentHashMap<String, FileLoadOperation> loadOperationPaths;
@ -294,18 +294,27 @@ public class FileLoader {
runningOperation = new LinkedList<FileLoadOperation>();
uploadOperationQueue = new LinkedList<FileUploadOperation>();
uploadOperationPaths = new ConcurrentHashMap<String, FileUploadOperation>();
uploadOperationPathsEnc = new ConcurrentHashMap<String, FileUploadOperation>();
loadOperationPaths = new ConcurrentHashMap<String, FileLoadOperation>();
loadOperationQueue = new LinkedList<FileLoadOperation>();
}
public void cancelUploadFile(final String location) {
public void cancelUploadFile(final String location, final boolean enc) {
Utilities.fileUploadQueue.postRunnable(new Runnable() {
@Override
public void run() {
FileUploadOperation operation = uploadOperationPaths.get(location);
if (operation != null) {
uploadOperationQueue.remove(operation);
operation.cancel();
if (!enc) {
FileUploadOperation operation = uploadOperationPaths.get(location);
if (operation != null) {
uploadOperationQueue.remove(operation);
operation.cancel();
}
} else {
FileUploadOperation operation = uploadOperationPathsEnc.get(location);
if (operation != null) {
uploadOperationQueue.remove(operation);
operation.cancel();
}
}
}
});
@ -319,17 +328,39 @@ public class FileLoader {
Utilities.fileUploadQueue.postRunnable(new Runnable() {
@Override
public void run() {
if (key != null) {
if (uploadOperationPathsEnc.containsKey(location)) {
return;
}
} else {
if (uploadOperationPaths.containsKey(location)) {
return;
}
}
FileUploadOperation operation = new FileUploadOperation(location, key, iv);
uploadOperationPaths.put(location, operation);
if (key != null) {
uploadOperationPathsEnc.put(location, operation);
} else {
uploadOperationPaths.put(location, operation);
}
operation.delegate = new FileUploadOperation.FileUploadOperationDelegate() {
@Override
public void didFinishUploadingFile(FileUploadOperation operation, final TLRPC.InputFile inputFile, final TLRPC.InputEncryptedFile inputEncryptedFile) {
NotificationCenter.Instance.postNotificationName(FileDidUpload, location, inputFile, inputEncryptedFile);
fileProgresses.remove(location);
Utilities.fileUploadQueue.postRunnable(new Runnable() {
@Override
public void run() {
uploadOperationPaths.remove(location);
Utilities.stageQueue.postRunnable(new Runnable() {
@Override
public void run() {
NotificationCenter.Instance.postNotificationName(FileDidUpload, location, inputFile, inputEncryptedFile);
fileProgresses.remove(location);
}
});
if (key != null) {
uploadOperationPathsEnc.remove(location);
} else {
uploadOperationPaths.remove(location);
}
currentUploadOperationsCount--;
if (currentUploadOperationsCount < 2) {
FileUploadOperation operation = uploadOperationQueue.poll();
@ -343,15 +374,24 @@ public class FileLoader {
}
@Override
public void didFailedUploadingFile(FileUploadOperation operation) {
fileProgresses.remove(location);
if (operation.state != 2) {
NotificationCenter.Instance.postNotificationName(FileDidFailUpload, location);
}
public void didFailedUploadingFile(final FileUploadOperation operation) {
Utilities.fileUploadQueue.postRunnable(new Runnable() {
@Override
public void run() {
uploadOperationPaths.remove(location);
Utilities.stageQueue.postRunnable(new Runnable() {
@Override
public void run() {
fileProgresses.remove(location);
if (operation.state != 2) {
NotificationCenter.Instance.postNotificationName(FileDidFailUpload, location, key != null);
}
}
});
if (key != null) {
uploadOperationPathsEnc.remove(location);
} else {
uploadOperationPaths.remove(location);
}
currentUploadOperationsCount--;
if (currentUploadOperationsCount < 2) {
FileUploadOperation operation = uploadOperationQueue.poll();
@ -375,7 +415,7 @@ public class FileLoader {
Utilities.RunOnUIThread(new Runnable() {
@Override
public void run() {
NotificationCenter.Instance.postNotificationName(FileUploadProgressChanged, location, progress);
NotificationCenter.Instance.postNotificationName(FileUploadProgressChanged, location, progress, key != null);
}
});
}

View File

@ -8,9 +8,6 @@
package org.telegram.messenger;
import org.telegram.TL.TLObject;
import org.telegram.TL.TLRPC;
import java.io.File;
import java.io.FileInputStream;
import java.math.BigInteger;
@ -134,7 +131,7 @@ public class FileUploadOperation {
}
System.arraycopy(readBuffer, 0, sendBuffer, 0, readed);
if (key != null) {
sendBuffer = Utilities.aesIgeEncryption(sendBuffer, key, iv, true, true);
sendBuffer = Utilities.aesIgeEncryption(sendBuffer, key, iv, true, true, 0);
}
mdEnc.update(sendBuffer, 0, readed + toAdd);
if (isBigFile) {

View File

@ -9,20 +9,50 @@
package org.telegram.messenger;
import android.app.Activity;
import android.content.ComponentName;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.support.v4.content.WakefulBroadcastReceiver;
import android.os.PowerManager;
public class GcmBroadcastReceiver extends WakefulBroadcastReceiver {
public class GcmBroadcastReceiver extends BroadcastReceiver {
public static final int NOTIFICATION_ID = 1;
@Override
public void onReceive(final Context context, final Intent intent) {
FileLog.d("tmessages", "GCM received intent: " + intent);
ComponentName comp = new ComponentName(context.getPackageName(), GcmService.class.getName());
startWakefulService(context, (intent.setComponent(comp)));
if (intent.getAction().equals("com.google.android.c2dm.intent.RECEIVE")) {
PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
final PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "lock");
wl.acquire();
// SharedPreferences preferences = context.getSharedPreferences("Notifications", Context.MODE_PRIVATE);
// boolean globalEnabled = preferences.getBoolean("EnableAll", true);
// if (!globalEnabled) {
// FileLog.d("tmessages", "GCM disabled");
// return;
// }
Thread thread = new Thread(new Runnable() {
public void run() {
ConnectionsManager.Instance.resumeNetworkMaybe();
wl.release();
}
});
thread.setPriority(Thread.MAX_PRIORITY);
thread.start();
} else if (intent.getAction().equals("com.google.android.c2dm.intent.REGISTRATION")) {
String registration = intent.getStringExtra("registration_id");
if (intent.getStringExtra("error") != null) {
FileLog.e("tmessages", "Registration failed, should try again later.");
} else if (intent.getStringExtra("unregistered") != null) {
FileLog.e("tmessages", "unregistration done, new messages from the authorized sender will be rejected");
} else if (registration != null) {
FileLog.e("tmessages", "registration id = " + registration);
}
}
setResultCode(Activity.RESULT_OK);
}
}

View File

@ -1,42 +0,0 @@
/*
* This is the source code of Telegram for Android v. 1.3.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
*
* Copyright Nikolai Kudashov, 2013.
*/
package org.telegram.messenger;
import android.app.IntentService;
import android.content.Intent;
public class GcmService extends IntentService {
public GcmService() {
super("GcmService");
}
@Override
protected void onHandleIntent(Intent intent) {
if (intent.getAction().equals("com.google.android.c2dm.intent.RECEIVE")) {
// SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Context.MODE_PRIVATE);
// boolean globalEnabled = preferences.getBoolean("EnableAll", true);
// if (!globalEnabled) {
// FileLog.d("tmessages", "GCM disabled");
// return;
// }
ConnectionsManager.Instance.resumeNetworkMaybe();
} else if (intent.getAction().equals("com.google.android.c2dm.intent.REGISTRATION")) {
String registration = intent.getStringExtra("registration_id");
if (intent.getStringExtra("error") != null) {
FileLog.e("tmessages", "Registration failed, should try again later.");
} else if (intent.getStringExtra("unregistered") != null) {
FileLog.e("tmessages", "unregistration done, new messages from the authorized sender will be rejected");
} else if (registration != null) {
FileLog.e("tmessages", "registration id = " + registration);
}
}
GcmBroadcastReceiver.completeWakefulIntent(intent);
}
}

View File

@ -8,12 +8,9 @@
package org.telegram.messenger;
import org.telegram.TL.TLClassStore;
import org.telegram.TL.TLObject;
import org.telegram.TL.TLRPC;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
@ -28,7 +25,7 @@ public class HandshakeAction extends Action implements TcpConnection.TcpConnecti
private byte[] authNewNonce;
private byte[] authKey;
private byte[] authKeyId;
private long authKeyId;
private boolean processedPQRes;
@ -64,7 +61,7 @@ public class HandshakeAction extends Action implements TcpConnection.TcpConnecti
authServerNonce = null;
authNewNonce = null;
authKey = null;
authKeyId = null;
authKeyId = 0;
processedPQRes = false;
reqPQMsgData = null;
reqDHMsgData = null;
@ -325,7 +322,7 @@ 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);
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);
@ -401,8 +398,11 @@ public class HandshakeAction extends Action implements TcpConnection.TcpConnecti
authKey = correctedAuth;
}
byte[] authKeyHash = Utilities.computeSHA1(authKey);
authKeyId = new byte[8];
System.arraycopy(authKeyHash, authKeyHash.length - 8, authKeyId, 0, 8);
byte[] authKeyArr = new byte[8];
System.arraycopy(authKeyHash, authKeyHash.length - 8, authKeyArr, 0, 8);
ByteBuffer buffer = ByteBuffer.wrap(authKeyArr);
buffer.order(ByteOrder.LITTLE_ENDIAN);
authKeyId = buffer.getLong();
SerializedData serverSaltData = new SerializedData();
for (int i = 7; i >= 0; i--) {
@ -443,7 +443,7 @@ public class HandshakeAction extends Action implements TcpConnection.TcpConnecti
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);
setClientDhParams.encrypted_data = Utilities.aesIgeEncryption(clientDataWithHash.toByteArray(), tmpAesKey.toByteArray(), tmpAesIv.toByteArray(), true, false, 0);
TLRPC.TL_msgs_ack msgsAck = new TLRPC.TL_msgs_ack();
msgsAck.msg_ids = new ArrayList<Long>();
@ -590,21 +590,20 @@ public class HandshakeAction extends Action implements TcpConnection.TcpConnecti
}
@Override
public void tcpConnectionReceivedData(TcpConnection connection, byte[] data) {
SerializedData is = new SerializedData(data);
public void tcpConnectionReceivedData(TcpConnection connection, ByteBufferDesc data, int length) {
long keyId = is.readInt64();
long keyId = data.readInt64();
if (keyId == 0) {
long messageId = is.readInt64();
long messageId = data.readInt64();
if (processedMessageIds.contains(messageId)) {
FileLog.d("tmessages", String.format("===== Duplicate message id %d received, ignoring", messageId));
return;
}
int messageLength = is.readInt32();
int messageLength = data.readInt32();
int constructor = is.readInt32();
TLObject object = TLClassStore.Instance().TLdeserialize(is, constructor);
int constructor = data.readInt32();
TLObject object = TLClassStore.Instance().TLdeserialize(data, constructor);
if (object != null) {
processedMessageIds.add(messageId);

View File

@ -0,0 +1,454 @@
/*
* This is the source code of Telegram for Android v. 1.3.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
*
* Copyright Nikolai Kudashov, 2013-2014.
*/
package org.telegram.messenger;
import android.content.Context;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaRecorder;
import android.os.Vibrator;
import org.telegram.objects.MessageObject;
import org.telegram.ui.ApplicationLoader;
import java.io.File;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Timer;
import java.util.TimerTask;
public class MediaController implements NotificationCenter.NotificationCenterDelegate {
public static interface FileDownloadProgressListener {
public void onFailedDownload(String fileName);
public void onSuccessDownload(String fileName);
public void onProgressDownload(String fileName, float progress);
public int getObserverTag();
}
public final static int audioProgressDidChanged = 50001;
public final static int audioDidReset = 50002;
public final static int recordProgressChanged = 50003;
public static MediaController Instance = new MediaController();
private HashMap<String, ArrayList<WeakReference<FileDownloadProgressListener>>> loadingFileObservers = new HashMap<String, ArrayList<WeakReference<FileDownloadProgressListener>>>();
private HashMap<Integer, String> observersByTag = new HashMap<Integer, String>();
private boolean listenerInProgress = false;
private HashMap<String, FileDownloadProgressListener> addLaterArray = new HashMap<String, FileDownloadProgressListener>();
private ArrayList<FileDownloadProgressListener> deleteLaterArray = new ArrayList<FileDownloadProgressListener>();
private boolean isPaused = false;
private MediaPlayer audioPlayer = null;
private int lastProgress = 0;
private MessageObject playingMessageObject;
private MediaRecorder audioRecorder = null;
private TLRPC.TL_audio recordingAudio = null;
private File recordingAudioFile = null;
private long recordStartTime;
private long recordDialogId;
private final Integer sync = 1;
private int lastTag = 0;
public MediaController () {
NotificationCenter.Instance.addObserver(this, FileLoader.FileDidFailedLoad);
NotificationCenter.Instance.addObserver(this, FileLoader.FileDidLoaded);
NotificationCenter.Instance.addObserver(this, FileLoader.FileLoadProgressChanged);
Timer progressTimer = new Timer();
progressTimer.schedule(new TimerTask() {
@Override
public void run() {
synchronized (sync) {
Utilities.RunOnUIThread(new Runnable() {
@Override
public void run() {
if (playingMessageObject != null && audioPlayer != null && !isPaused) {
try {
int progress = audioPlayer.getCurrentPosition();
if (progress <= lastProgress) {
return;
}
lastProgress = progress;
final float value = (float)lastProgress / (float)audioPlayer.getDuration();
playingMessageObject.audioProgress = value;
playingMessageObject.audioProgressSec = lastProgress / 1000;
NotificationCenter.Instance.postNotificationName(audioProgressDidChanged, playingMessageObject.messageOwner.id, value);
} catch (Exception e) {
FileLog.e("tmessages", e);
}
}
if (audioRecorder != null) {
NotificationCenter.Instance.postNotificationName(recordProgressChanged, System.currentTimeMillis() - recordStartTime);
}
}
});
}
}
}, 100, 17);
}
public void cleanup() {
clenupPlayer(false);
}
public int generateObserverTag() {
return lastTag++;
}
public void addLoadingFileObserver(String fileName, FileDownloadProgressListener observer) {
if (listenerInProgress) {
addLaterArray.put(fileName, observer);
return;
}
removeLoadingFileObserver(observer);
ArrayList<WeakReference<FileDownloadProgressListener>> arrayList = loadingFileObservers.get(fileName);
if (arrayList == null) {
arrayList = new ArrayList<WeakReference<FileDownloadProgressListener>>();
loadingFileObservers.put(fileName, arrayList);
}
arrayList.add(new WeakReference<FileDownloadProgressListener>(observer));
observersByTag.put(observer.getObserverTag(), fileName);
}
public void removeLoadingFileObserver(FileDownloadProgressListener observer) {
if (listenerInProgress) {
deleteLaterArray.add(observer);
return;
}
String fileName = observersByTag.get(observer.getObserverTag());
if (fileName != null) {
ArrayList<WeakReference<FileDownloadProgressListener>> arrayList = loadingFileObservers.get(fileName);
if (arrayList != null) {
for (int a = 0; a < arrayList.size(); a++) {
WeakReference<FileDownloadProgressListener> reference = arrayList.get(a);
if (reference.get() == null || reference.get() == observer) {
arrayList.remove(a);
a--;
}
}
if (arrayList.isEmpty()) {
loadingFileObservers.remove(fileName);
}
}
observersByTag.remove(observer.getObserverTag());
}
}
private void processLaterArrays() {
for (HashMap.Entry<String, FileDownloadProgressListener> listener : addLaterArray.entrySet()) {
addLoadingFileObserver(listener.getKey(), listener.getValue());
}
addLaterArray.clear();
for (FileDownloadProgressListener listener : deleteLaterArray) {
removeLoadingFileObserver(listener);
}
deleteLaterArray.clear();
}
@Override
public void didReceivedNotification(int id, Object... args) {
if (id == FileLoader.FileDidFailedLoad) {
listenerInProgress = true;
String fileName = (String)args[0];
ArrayList<WeakReference<FileDownloadProgressListener>> arrayList = loadingFileObservers.get(fileName);
if (arrayList != null) {
for (WeakReference<FileDownloadProgressListener> reference : arrayList) {
if (reference.get() != null) {
reference.get().onFailedDownload(fileName);
observersByTag.remove(reference.get().getObserverTag());
}
}
loadingFileObservers.remove(fileName);
}
listenerInProgress = false;
processLaterArrays();
} else if (id == FileLoader.FileDidLoaded) {
listenerInProgress = true;
String fileName = (String)args[0];
ArrayList<WeakReference<FileDownloadProgressListener>> arrayList = loadingFileObservers.get(fileName);
if (arrayList != null) {
for (WeakReference<FileDownloadProgressListener> reference : arrayList) {
if (reference.get() != null) {
reference.get().onSuccessDownload(fileName);
observersByTag.remove(reference.get().getObserverTag());
}
}
loadingFileObservers.remove(fileName);
}
listenerInProgress = false;
processLaterArrays();
} else if (id == FileLoader.FileLoadProgressChanged) {
listenerInProgress = true;
String fileName = (String)args[0];
ArrayList<WeakReference<FileDownloadProgressListener>> arrayList = loadingFileObservers.get(fileName);
if (arrayList != null) {
Float progress = (Float)args[1];
for (WeakReference<FileDownloadProgressListener> reference : arrayList) {
if (reference.get() != null) {
reference.get().onProgressDownload(fileName, progress);
}
}
}
listenerInProgress = false;
processLaterArrays();
}
}
private void clenupPlayer(boolean notify) {
if (audioPlayer != null) {
try {
audioPlayer.stop();
} catch (Exception e) {
FileLog.e("tmessages", e);
}
try {
audioPlayer.release();
audioPlayer = null;
} catch (Exception e) {
FileLog.e("tmessages", e);
}
lastProgress = 0;
isPaused = false;
MessageObject lastFile = playingMessageObject;
playingMessageObject.audioProgress = 0.0f;
playingMessageObject.audioProgressSec = 0;
playingMessageObject = null;
if (notify) {
NotificationCenter.Instance.postNotificationName(audioDidReset, lastFile.messageOwner.id);
}
}
}
public boolean seekToProgress(MessageObject messageObject, float progress) {
if (audioPlayer == null || messageObject == null || playingMessageObject == null || playingMessageObject != null && playingMessageObject.messageOwner.id != messageObject.messageOwner.id) {
return false;
}
try {
int seekTo = (int)(audioPlayer.getDuration() * progress);
audioPlayer.seekTo(seekTo);
lastProgress = seekTo;
} catch (Exception e) {
FileLog.e("tmessages", e);
return false;
}
return true;
}
public boolean playAudio(MessageObject messageObject) {
if (messageObject == null) {
return false;
}
if (audioPlayer != null && playingMessageObject != null && messageObject.messageOwner.id == playingMessageObject.messageOwner.id) {
if (isPaused) {
resumeAudio(messageObject);
}
return true;
}
clenupPlayer(true);
try {
audioPlayer = new MediaPlayer();
audioPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
File cacheFile = new File(Utilities.getCacheDir(), messageObject.getFileName());
audioPlayer.setDataSource(cacheFile.getAbsolutePath());
audioPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mediaPlayer) {
clenupPlayer(true);
}
});
audioPlayer.prepare();
audioPlayer.start();
} catch (Exception e) {
FileLog.e("tmessages", e);
if (audioPlayer != null) {
audioPlayer.release();
audioPlayer = null;
isPaused = false;
playingMessageObject = null;
}
return false;
}
isPaused = false;
lastProgress = 0;
playingMessageObject = messageObject;
try {
if (playingMessageObject.audioProgress != 0) {
int seekTo = (int)(audioPlayer.getDuration() * playingMessageObject.audioProgress);
audioPlayer.seekTo(seekTo);
}
} catch (Exception e2) {
playingMessageObject.audioProgress = 0;
playingMessageObject.audioProgressSec = 0;
FileLog.e("tmessages", e2);
}
return true;
}
public void stopAudio() {
if (audioPlayer == null || playingMessageObject == null) {
return;
}
try {
audioPlayer.stop();
} catch (Exception e) {
FileLog.e("tmessages", e);
}
try {
audioPlayer.release();
audioPlayer = null;
} catch (Exception e) {
FileLog.e("tmessages", e);
}
playingMessageObject = null;
isPaused = false;
}
public boolean pauseAudio(MessageObject messageObject) {
if (audioPlayer == null || messageObject == null || playingMessageObject == null || playingMessageObject != null && playingMessageObject.messageOwner.id != messageObject.messageOwner.id) {
return false;
}
try {
audioPlayer.pause();
isPaused = true;
} catch (Exception e) {
FileLog.e("tmessages", e);
isPaused = false;
return false;
}
return true;
}
public boolean resumeAudio(MessageObject messageObject) {
if (audioPlayer == null || messageObject == null || playingMessageObject == null || playingMessageObject != null && playingMessageObject.messageOwner.id != messageObject.messageOwner.id) {
return false;
}
try {
audioPlayer.start();
isPaused = false;
} catch (Exception e) {
FileLog.e("tmessages", e);
return false;
}
return true;
}
public boolean isPlayingAudio(MessageObject messageObject) {
return !(audioPlayer == null || messageObject == null || playingMessageObject == null || playingMessageObject != null && playingMessageObject.messageOwner.id != messageObject.messageOwner.id);
}
public boolean isAudioPaused() {
return isPaused;
}
public boolean startRecording(long dialog_id) {
if (audioRecorder != null) {
return false;
}
recordingAudio = new TLRPC.TL_audio();
recordingAudio.dc_id = Integer.MIN_VALUE;
recordingAudio.id = UserConfig.lastLocalId;
recordingAudio.user_id = UserConfig.clientUserId;
UserConfig.lastLocalId--;
UserConfig.saveConfig(false);
recordingAudioFile = new File(Utilities.getCacheDir(), MessageObject.getAttachFileName(recordingAudio));
audioRecorder = new MediaRecorder();
audioRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
audioRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
audioRecorder.setOutputFile(recordingAudioFile.getAbsolutePath());
if(android.os.Build.VERSION.SDK_INT >= 10) {
audioRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
} else {
audioRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
}
audioRecorder.setAudioSamplingRate(24000);
audioRecorder.setAudioChannels(1);
audioRecorder.setAudioEncodingBitRate(16000);
try {
audioRecorder.prepare();
audioRecorder.start();
recordStartTime = System.currentTimeMillis();
recordDialogId = dialog_id;
} catch (Exception e) {
FileLog.e("tmessages", e);
recordingAudio = null;
recordingAudioFile.delete();
recordingAudioFile = null;
try {
audioRecorder.release();
audioRecorder = null;
} catch (Exception e2) {
FileLog.e("tmessages", e2);
}
return false;
}
try {
Vibrator v = (Vibrator) ApplicationLoader.applicationContext.getSystemService(Context.VIBRATOR_SERVICE);
v.vibrate(20);
} catch (Exception e) {
FileLog.e("tmessages", e);
}
return true;
}
public void stopRecording(boolean send) {
if (audioRecorder == null) {
return;
}
try {
audioRecorder.stop();
if (send) {
recordingAudio.date = ConnectionsManager.Instance.getCurrentTime();
recordingAudio.size = (int)recordingAudioFile.length();
recordingAudio.path = recordingAudioFile.getAbsolutePath();
long duration = System.currentTimeMillis() - recordStartTime;
recordingAudio.duration = (int)(duration / 1000);
if (duration > 500) {
MessagesController.Instance.sendMessage(recordingAudio, recordDialogId);
} else {
recordingAudioFile.delete();
}
}
} catch (Exception e) {
FileLog.e("tmessages", e);
if (recordingAudioFile != null) {
recordingAudioFile.delete();
}
}
try {
if (audioRecorder != null) {
audioRecorder.release();
audioRecorder = null;
}
} catch (Exception e) {
FileLog.e("tmessages", e);
}
recordingAudio = null;
recordingAudioFile = null;
try {
Vibrator v = (Vibrator) ApplicationLoader.applicationContext.getSystemService(Context.VIBRATOR_SERVICE);
v.vibrate(20);
} catch (Exception e) {
FileLog.e("tmessages", e);
}
}
}

View File

@ -32,9 +32,6 @@ import android.support.v7.app.ActionBarActivity;
import android.text.Html;
import android.util.SparseArray;
import org.telegram.TL.TLClassStore;
import org.telegram.TL.TLObject;
import org.telegram.TL.TLRPC;
import org.telegram.objects.MessageObject;
import org.telegram.objects.PhotoObject;
import org.telegram.ui.ApplicationLoader;
@ -63,7 +60,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter
public ConcurrentHashMap<Long, ArrayList<PrintingUser>> printingUsers = new ConcurrentHashMap<Long, ArrayList<PrintingUser>>(100, 1.0f, 2);
public HashMap<Long, CharSequence> printingStrings = new HashMap<Long, CharSequence>();
private HashMap<String, DelayedMessage> delayedMessages = new HashMap<String, DelayedMessage>();
private HashMap<String, ArrayList<DelayedMessage>> delayedMessages = new HashMap<String, ArrayList<DelayedMessage>>();
public SparseArray<MessageObject> sendingMessages = new SparseArray<MessageObject>();
public SparseArray<TLRPC.User> hidenAddToContacts = new SparseArray<TLRPC.User>();
private SparseArray<TLRPC.EncryptedChat> acceptingChats = new SparseArray<TLRPC.EncryptedChat>();
@ -85,12 +82,15 @@ public class MessagesController implements NotificationCenter.NotificationCenter
public boolean registeringForPush = false;
private long lastSoundPlay = 0;
private long lastStatusUpdateTime = 0;
private boolean offlineSended = false;
private long statusRequest = 0;
private int statusSettingState = 0;
private boolean offlineSent = false;
private String uploadingAvatar = null;
private SoundPool soundPool;
private int sound;
public static SecureRandom random = new SecureRandom();
public boolean enableJoined = true;
public int fontSize = Utilities.dp(16);
public long scheduleContactsReload = 0;
private class UserActionUpdates extends TLRPC.Updates {
@ -183,6 +183,8 @@ public class MessagesController implements NotificationCenter.NotificationCenter
addSupportUser();
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE);
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);
@ -226,7 +228,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter
if (id == FileLoader.FileDidUpload) {
fileDidUploaded((String)args[0], (TLRPC.InputFile)args[1], (TLRPC.InputEncryptedFile)args[2]);
} else if (id == FileLoader.FileDidFailUpload) {
fileDidFailedUpload((String) args[0]);
fileDidFailedUpload((String) args[0], (Boolean) args[1]);
} else if (id == messageReceivedByServer) {
Integer msgId = (Integer)args[0];
MessageObject obj = dialogMessage.get(msgId);
@ -268,6 +270,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter
public void cleanUp() {
ContactsController.Instance.cleanup();
MediaController.Instance.cleanup();
dialogs_dict.clear();
dialogs.clear();
@ -297,9 +300,11 @@ public class MessagesController implements NotificationCenter.NotificationCenter
firstGettingTask = false;
updatingState = false;
lastStatusUpdateTime = 0;
offlineSended = false;
offlineSent = false;
registeringForPush = false;
uploadingAvatar = null;
statusRequest = 0;
statusSettingState = 0;
addSupportUser();
}
@ -737,32 +742,56 @@ public class MessagesController implements NotificationCenter.NotificationCenter
if (UserConfig.clientUserId != 0) {
if (scheduleContactsReload != 0 && currentTime > scheduleContactsReload) {
ContactsController.Instance.performSyncPhoneBook(ContactsController.Instance.getContactsCopy(ContactsController.Instance.contactsBook), true, false);
ContactsController.Instance.performSyncPhoneBook(ContactsController.Instance.getContactsCopy(ContactsController.Instance.contactsBook), true, false, true);
scheduleContactsReload = 0;
}
if (ApplicationLoader.lastPauseTime == 0) {
if (lastStatusUpdateTime != -1 && (lastStatusUpdateTime == 0 || lastStatusUpdateTime <= System.currentTimeMillis() - 55000 || offlineSended)) {
lastStatusUpdateTime = -1;
if (statusSettingState != 1 && (lastStatusUpdateTime == 0 || lastStatusUpdateTime <= System.currentTimeMillis() - 55000 || offlineSent)) {
statusSettingState = 1;
if (statusRequest != 0) {
ConnectionsManager.Instance.cancelRpc(statusRequest, true);
}
TLRPC.TL_account_updateStatus req = new TLRPC.TL_account_updateStatus();
req.offline = false;
ConnectionsManager.Instance.performRpc(req, new RPCRequest.RPCRequestDelegate() {
statusRequest = ConnectionsManager.Instance.performRpc(req, new RPCRequest.RPCRequestDelegate() {
@Override
public void run(TLObject response, TLRPC.TL_error error) {
lastStatusUpdateTime = System.currentTimeMillis();
if (error == null) {
lastStatusUpdateTime = System.currentTimeMillis();
offlineSent = false;
statusSettingState = 0;
} else {
if (lastStatusUpdateTime != 0) {
lastStatusUpdateTime += 5000;
}
}
statusRequest = 0;
}
}, null, true, RPCRequest.RPCRequestClassGeneric);
offlineSended = false;
}
} else if (!offlineSended && ApplicationLoader.lastPauseTime <= System.currentTimeMillis() - 2000) {
} else if (statusSettingState != 2 && !offlineSent && ApplicationLoader.lastPauseTime <= System.currentTimeMillis() - 2000) {
statusSettingState = 2;
if (statusRequest != 0) {
ConnectionsManager.Instance.cancelRpc(statusRequest, true);
}
TLRPC.TL_account_updateStatus req = new TLRPC.TL_account_updateStatus();
req.offline = true;
ConnectionsManager.Instance.performRpc(req, new RPCRequest.RPCRequestDelegate() {
statusRequest = ConnectionsManager.Instance.performRpc(req, new RPCRequest.RPCRequestDelegate() {
@Override
public void run(TLObject response, TLRPC.TL_error error) {
if (error == null) {
offlineSent = true;
} else {
if (lastStatusUpdateTime != 0) {
lastStatusUpdateTime += 5000;
}
}
statusRequest = 0;
}
}, null, true, RPCRequest.RPCRequestClassGeneric);
offlineSended = true;
}
if (updatesStartWaitTime != 0 && updatesStartWaitTime + 1500 < currentTime) {
@ -972,7 +1001,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter
public void run() {
for (TLRPC.User u : messagesRes.users) {
if (isCache) {
if (u.id == UserConfig.clientUserId || u.id == 333000) {
if (u.id == UserConfig.clientUserId || u.id / 1000 == 333) {
users.put(u.id, u);
} else {
users.putIfAbsent(u.id, u);
@ -1022,6 +1051,21 @@ public class MessagesController implements NotificationCenter.NotificationCenter
}
}
public void processDialogsUpdateRead(final HashMap<Long, Integer>dialogsToUpdate) {
Utilities.RunOnUIThread(new Runnable() {
@Override
public void run() {
for (HashMap.Entry<Long, Integer> entry : dialogsToUpdate.entrySet()) {
TLRPC.TL_dialog currentDialog = dialogs_dict.get(entry.getKey());
if (currentDialog != null) {
currentDialog.unread_count = entry.getValue();
}
}
NotificationCenter.Instance.postNotificationName(dialogsNeedReload);
}
});
}
public void processDialogsUpdate(final TLRPC.messages_Dialogs dialogsRes, ArrayList<TLRPC.EncryptedChat> encChats) {
Utilities.stageQueue.postRunnable(new Runnable() {
@Override
@ -1130,7 +1174,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter
public void run() {
for (TLRPC.User u : dialogsRes.users) {
if (isCache) {
if (u.id == UserConfig.clientUserId || u.id == 333000) {
if (u.id == UserConfig.clientUserId || u.id / 1000 == 333) {
users.put(u.id, u);
} else {
users.putIfAbsent(u.id, u);
@ -1198,7 +1242,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter
public void run() {
for (TLRPC.User u : dialogsRes.users) {
if (isCache) {
if (u.id == UserConfig.clientUserId || u.id == 333000) {
if (u.id == UserConfig.clientUserId || u.id / 1000 == 333) {
users.put(u.id, u);
} else {
users.putIfAbsent(u.id, u);
@ -1454,18 +1498,29 @@ public class MessagesController implements NotificationCenter.NotificationCenter
public void cancelSendingMessage(MessageObject object) {
String keyToRemvoe = null;
for (HashMap.Entry<String, DelayedMessage> entry : delayedMessages.entrySet()) {
if (entry.getValue().obj.messageOwner.id == object.messageOwner.id) {
keyToRemvoe = entry.getKey();
break;
boolean enc = false;
for (HashMap.Entry<String, ArrayList<DelayedMessage>> entry : delayedMessages.entrySet()) {
ArrayList<DelayedMessage> messages = entry.getValue();
for (int a = 0; a < messages.size(); a++) {
DelayedMessage message = messages.get(a);
if (message.obj.messageOwner.id == object.messageOwner.id) {
messages.remove(a);
if (messages.size() == 0) {
keyToRemvoe = entry.getKey();
if (message.sendEncryptedRequest != null) {
enc = true;
}
}
break;
}
}
}
if (keyToRemvoe != null) {
ArrayList<Integer> messages = new ArrayList<Integer>();
messages.add(object.messageOwner.id);
FileLoader.Instance.cancelUploadFile(keyToRemvoe);
deleteMessages(messages);
FileLoader.Instance.cancelUploadFile(keyToRemvoe, enc);
}
ArrayList<Integer> messages = new ArrayList<Integer>();
messages.add(object.messageOwner.id);
deleteMessages(messages);
}
private long getNextRandomId() {
@ -1592,6 +1647,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter
newMsg.media = msgObj.messageOwner.media;
newMsg.message = msgObj.messageOwner.message;
newMsg.fwd_msg_id = msgObj.messageOwner.id;
newMsg.attachPath = msgObj.messageOwner.attachPath;
type = 4;
} else if (msgObj.type == 11) {
newMsg.fwd_from_id = msgObj.messageOwner.from_id;
@ -1607,6 +1663,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter
newMsg.media = msgObj.messageOwner.media;
newMsg.message = msgObj.messageOwner.message;
newMsg.fwd_msg_id = msgObj.messageOwner.id;
newMsg.attachPath = msgObj.messageOwner.attachPath;
type = 4;
}
} else if (location != null) {
@ -1889,7 +1946,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter
}
}
private void processSendedMessage(TLRPC.Message newMsg, TLRPC.Message sentMessage, TLRPC.EncryptedFile file, TLRPC.DecryptedMessage decryptedMessage) {
private void processSentMessage(TLRPC.Message newMsg, TLRPC.Message sentMessage, TLRPC.EncryptedFile file, TLRPC.DecryptedMessage decryptedMessage) {
if (sentMessage != null) {
if (sentMessage.media instanceof TLRPC.TL_messageMediaPhoto && sentMessage.media.photo != null && newMsg.media instanceof TLRPC.TL_messageMediaPhoto && newMsg.media.photo != null) {
for (TLRPC.PhotoSize size : sentMessage.media.photo.sizes) {
@ -1946,8 +2003,8 @@ public class MessagesController implements NotificationCenter.NotificationCenter
File cacheFile = new File(Utilities.getCacheDir(), fileName);
File cacheFile2 = new File(Utilities.getCacheDir(), fileName2);
cacheFile.renameTo(cacheFile2);
sentMessage.media.audio.dc_id = newMsg.media.audio.dc_id;
sentMessage.media.audio.id = newMsg.media.audio.id;
newMsg.media.audio.dc_id = sentMessage.media.audio.dc_id;
newMsg.media.audio.id = sentMessage.media.audio.id;
}
} else if (file != null) {
if (newMsg.media instanceof TLRPC.TL_messageMediaPhoto && newMsg.media.photo != null) {
@ -2067,7 +2124,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter
dataForEncryption.writeByte(b[0]);
}
byte[] encryptedData = Utilities.aesIgeEncryption(dataForEncryption.toByteArray(), keyData.aesKey, keyData.aesIv, true, false);
byte[] encryptedData = Utilities.aesIgeEncryption(dataForEncryption.toByteArray(), keyData.aesKey, keyData.aesIv, true, false, 0);
data = new SerializedData();
data.writeInt64(chat.key_fingerprint);
@ -2101,7 +2158,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter
TLRPC.messages_SentEncryptedMessage res = (TLRPC.messages_SentEncryptedMessage)response;
newMsgObj.messageOwner.date = res.date;
if (res.file instanceof TLRPC.TL_encryptedFile) {
processSendedMessage(newMsgObj.messageOwner, null, res.file, req);
processSentMessage(newMsgObj.messageOwner, null, res.file, req);
}
MessagesStorage.Instance.updateMessageStateAndId(newMsgObj.messageOwner.random_id, newMsgObj.messageOwner.id, newMsgObj.messageOwner.id, res.date, true);
Utilities.RunOnUIThread(new Runnable() {
@ -2132,7 +2189,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter
public void run(TLObject response, TLRPC.TL_error error) {
if (error == null) {
final int oldId = newMsgObj.messageOwner.id;
ArrayList<TLRPC.Message> sendedMessages = new ArrayList<TLRPC.Message>();
ArrayList<TLRPC.Message> sentMessages = new ArrayList<TLRPC.Message>();
if (response instanceof TLRPC.TL_messages_sentMessage) {
TLRPC.TL_messages_sentMessage res = (TLRPC.TL_messages_sentMessage)response;
@ -2158,9 +2215,9 @@ public class MessagesController implements NotificationCenter.NotificationCenter
}
} else if (response instanceof TLRPC.messages_StatedMessage) {
TLRPC.messages_StatedMessage res = (TLRPC.messages_StatedMessage)response;
sendedMessages.add(res.message);
sentMessages.add(res.message);
newMsgObj.messageOwner.id = res.message.id;
processSendedMessage(newMsgObj.messageOwner, res.message, null, null);
processSentMessage(newMsgObj.messageOwner, res.message, null, null);
if(MessagesStorage.lastSeqValue + 1 == res.seq) {
MessagesStorage.lastSeqValue = res.seq;
MessagesStorage.lastPtsValue = res.pts;
@ -2185,8 +2242,8 @@ public class MessagesController implements NotificationCenter.NotificationCenter
if (!res.messages.isEmpty()) {
TLRPC.Message message = res.messages.get(0);
newMsgObj.messageOwner.id = message.id;
sendedMessages.add(message);
processSendedMessage(newMsgObj.messageOwner, message, null, null);
sentMessages.add(message);
processSentMessage(newMsgObj.messageOwner, message, null, null);
}
if (MessagesStorage.lastSeqValue + 1 == res.seq) {
MessagesStorage.lastSeqValue = res.seq;
@ -2208,8 +2265,8 @@ public class MessagesController implements NotificationCenter.NotificationCenter
}
}
MessagesStorage.Instance.updateMessageStateAndId(newMsgObj.messageOwner.random_id, oldId, newMsgObj.messageOwner.id, 0, true);
if (!sendedMessages.isEmpty()) {
MessagesStorage.Instance.putMessages(sendedMessages, true, true);
if (!sentMessages.isEmpty()) {
MessagesStorage.Instance.putMessages(sentMessages, true, true);
}
Utilities.RunOnUIThread(new Runnable() {
@Override
@ -2245,74 +2302,87 @@ public class MessagesController implements NotificationCenter.NotificationCenter
}), true, RPCRequest.RPCRequestClassGeneric | RPCRequest.RPCRequestClassFailOnServerErrors | RPCRequest.RPCRequestClassCanCompress, ConnectionsManager.DEFAULT_DATACENTER_ID);
}
private void performSendDelayedMessage(final DelayedMessage message) {
Utilities.stageQueue.postRunnable(new Runnable() {
@Override
public void run() {
if (message.type == 0) {
String location = Utilities.getCacheDir() + "/" + message.location.volume_id + "_" + message.location.local_id + ".jpg";
delayedMessages.put(location, message);
if (message.sendRequest != null) {
FileLoader.Instance.uploadFile(location, null, null);
} else {
FileLoader.Instance.uploadFile(location, message.sendEncryptedRequest.media.key, message.sendEncryptedRequest.media.iv);
}
} 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";
delayedMessages.put(location, message);
FileLoader.Instance.uploadFile(location, null, null);
} else {
String location = message.videoLocation.path;
if (location == null) {
location = Utilities.getCacheDir() + "/" + message.videoLocation.id + ".mp4";
}
delayedMessages.put(location, message);
FileLoader.Instance.uploadFile(location, null, null);
}
} else {
String location = message.videoLocation.path;
if (location == null) {
location = Utilities.getCacheDir() + "/" + message.videoLocation.id + ".mp4";
}
delayedMessages.put(location, message);
FileLoader.Instance.uploadFile(location, message.sendEncryptedRequest.media.key, message.sendEncryptedRequest.media.iv);
}
} else if (message.type == 2) {
String location = message.documentLocation.path;
delayedMessages.put(location, message);
if (message.sendRequest != null) {
FileLoader.Instance.uploadFile(location, null, null);
} else {
FileLoader.Instance.uploadFile(location, message.sendEncryptedRequest.media.key, message.sendEncryptedRequest.media.iv);
}
} else if (message.type == 3) {
String location = message.audioLocation.path;
delayedMessages.put(location, message);
if (message.sendRequest != null) {
FileLoader.Instance.uploadFile(location, null, null);
} else {
FileLoader.Instance.uploadFile(location, message.sendEncryptedRequest.media.key, message.sendEncryptedRequest.media.iv);
}
}
}
});
private void putToDelayedMessages(String location, DelayedMessage message) {
ArrayList<DelayedMessage> arrayList = delayedMessages.get(location);
if (arrayList == null) {
arrayList = new ArrayList<DelayedMessage>();
delayedMessages.put(location, arrayList);
}
arrayList.add(message);
}
public void fileDidFailedUpload(final String location) {
private void performSendDelayedMessage(final DelayedMessage message) {
if (message.type == 0) {
String location = Utilities.getCacheDir() + "/" + message.location.volume_id + "_" + message.location.local_id + ".jpg";
putToDelayedMessages(location, message);
if (message.sendRequest != null) {
FileLoader.Instance.uploadFile(location, null, null);
} else {
FileLoader.Instance.uploadFile(location, message.sendEncryptedRequest.media.key, message.sendEncryptedRequest.media.iv);
}
} 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";
putToDelayedMessages(location, message);
FileLoader.Instance.uploadFile(location, null, null);
} else {
String location = message.videoLocation.path;
if (location == null) {
location = Utilities.getCacheDir() + "/" + message.videoLocation.id + ".mp4";
}
putToDelayedMessages(location, message);
FileLoader.Instance.uploadFile(location, null, null);
}
} else {
String location = message.videoLocation.path;
if (location == null) {
location = Utilities.getCacheDir() + "/" + message.videoLocation.id + ".mp4";
}
putToDelayedMessages(location, message);
FileLoader.Instance.uploadFile(location, message.sendEncryptedRequest.media.key, message.sendEncryptedRequest.media.iv);
}
} else if (message.type == 2) {
String location = message.documentLocation.path;
putToDelayedMessages(location, message);
if (message.sendRequest != null) {
FileLoader.Instance.uploadFile(location, null, null);
} else {
FileLoader.Instance.uploadFile(location, message.sendEncryptedRequest.media.key, message.sendEncryptedRequest.media.iv);
}
} else if (message.type == 3) {
String location = message.audioLocation.path;
putToDelayedMessages(location, message);
if (message.sendRequest != null) {
FileLoader.Instance.uploadFile(location, null, null);
} else {
FileLoader.Instance.uploadFile(location, message.sendEncryptedRequest.media.key, message.sendEncryptedRequest.media.iv);
}
}
}
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() {
DelayedMessage obj = delayedMessages.get(location);
if (obj != null) {
obj.obj.messageOwner.send_state = MESSAGE_SEND_STATE_SEND_ERROR;
sendingMessages.remove(obj.obj.messageOwner.id);
NotificationCenter.Instance.postNotificationName(messageSendError, obj.obj.messageOwner.id);
delayedMessages.remove(location);
ArrayList<DelayedMessage> 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.Instance.postNotificationName(messageSendError, obj.obj.messageOwner.id);
}
}
if (arr.isEmpty()) {
delayedMessages.remove(location);
}
}
}
});
@ -2372,31 +2442,40 @@ public class MessagesController implements NotificationCenter.NotificationCenter
Utilities.RunOnUIThread(new Runnable() {
@Override
public void run() {
DelayedMessage message = delayedMessages.get(location);
if (message != null) {
if (file != null) {
if (message.type == 0) {
message.sendRequest.media.file = file;
performSendMessageRequest(message.sendRequest, message.obj);
} else if (message.type == 1) {
if (message.sendRequest.media.thumb == null) {
message.sendRequest.media.thumb = file;
performSendDelayedMessage(message);
} else {
ArrayList<DelayedMessage> 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);
} 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);
}
} else if (message.type == 2) {
message.sendRequest.media.file = file;
performSendMessageRequest(message.sendRequest, message.obj);
} else if (message.type == 3) {
message.sendRequest.media.file = file;
performSendMessageRequest(message.sendRequest, message.obj);
}
} else if (message.type == 2) {
message.sendRequest.media.file = file;
performSendMessageRequest(message.sendRequest, message.obj);
} else if (message.type == 3) {
message.sendRequest.media.file = file;
performSendMessageRequest(message.sendRequest, message.obj);
arr.remove(a);
a--;
} else if (encryptedFile != null && message.sendEncryptedRequest != null) {
performSendEncryptedRequest(message.sendEncryptedRequest, message.obj, message.encryptedChat, encryptedFile);
arr.remove(a);
a--;
}
} else if (encryptedFile != null) {
performSendEncryptedRequest(message.sendEncryptedRequest, message.obj, message.encryptedChat, encryptedFile);
}
delayedMessages.remove(location);
if (arr.isEmpty()) {
delayedMessages.remove(location);
}
}
}
});
@ -2768,6 +2847,18 @@ public class MessagesController implements NotificationCenter.NotificationCenter
}
public void unregistedPush() {
if (UserConfig.registeredForPush && UserConfig.pushString.length() == 0) {
TLRPC.TL_account_unregisterDevice req = new TLRPC.TL_account_unregisterDevice();
req.token = UserConfig.pushString;
req.token_type = 2;
ConnectionsManager.Instance.performRpc(req, new RPCRequest.RPCRequestDelegate() {
@Override
public void run(TLObject response, TLRPC.TL_error error) {
}
}, null, true, RPCRequest.RPCRequestClassGeneric);
}
TLRPC.TL_auth_logOut req2 = new TLRPC.TL_auth_logOut();
ConnectionsManager.Instance.performRpc(req2, new RPCRequest.RPCRequestDelegate() {
@Override
@ -2775,19 +2866,6 @@ public class MessagesController implements NotificationCenter.NotificationCenter
}
}, null, true, RPCRequest.RPCRequestClassGeneric);
if (!UserConfig.registeredForPush || UserConfig.pushString.length() == 0) {
return;
}
TLRPC.TL_account_unregisterDevice req = new TLRPC.TL_account_unregisterDevice();
req.token = UserConfig.pushString;
req.token_type = 2;
ConnectionsManager.Instance.performRpc(req, new RPCRequest.RPCRequestDelegate() {
@Override
public void run(TLObject response, TLRPC.TL_error error) {
}
}, null, true, RPCRequest.RPCRequestClassGeneric);
}
public void registerForPush(final String regid) {
@ -3831,22 +3909,12 @@ public class MessagesController implements NotificationCenter.NotificationCenter
toDbUser.id = update.user_id;
TLRPC.User currentUser = users.get(update.user_id);
if (update instanceof TLRPC.TL_updateUserStatus) {
if (!(update.status instanceof TLRPC.TL_userStatusEmpty)) {
if (currentUser != null) {
currentUser.id = update.user_id;
currentUser.status = update.status;
if (update.status instanceof TLRPC.TL_userStatusOnline) {
currentUser.status.was_online = update.status.expires;
} else if (update.status instanceof TLRPC.TL_userStatusOffline) {
currentUser.status.expires = update.status.was_online;
} else {
currentUser.status.was_online = 0;
currentUser.status.expires = 0;
}
}
toDbUser.status = update.status;
dbUsersStatus.add(toDbUser);
if (currentUser != null) {
currentUser.id = update.user_id;
currentUser.status = update.status;
}
toDbUser.status = update.status;
dbUsersStatus.add(toDbUser);
} else if (update instanceof TLRPC.TL_updateUserName) {
if (currentUser != null) {
currentUser.first_name = update.first_name;
@ -3931,6 +3999,9 @@ public class MessagesController implements NotificationCenter.NotificationCenter
}
if (!markAsReadMessages.isEmpty() || !markAsReadEncrypted.isEmpty()) {
if (!markAsReadMessages.isEmpty()) {
MessagesStorage.Instance.updateDialogsWithReadedMessages(markAsReadMessages, true);
}
MessagesStorage.Instance.markMessagesAsRead(markAsReadMessages, markAsReadEncrypted, true);
}
if (!deletedMessages.isEmpty()) {
@ -3939,9 +4010,6 @@ public class MessagesController implements NotificationCenter.NotificationCenter
if (!deletedMessages.isEmpty()) {
MessagesStorage.Instance.updateDialogsWithDeletedMessages(deletedMessages, true);
}
if (!markAsReadMessages.isEmpty()) {
MessagesStorage.Instance.updateDialogsWithReadedMessages(markAsReadMessages, true);
}
if (!tasks.isEmpty()) {
for (TLRPC.TL_updateEncryptedMessagesRead update : tasks) {
MessagesStorage.Instance.createTaskForDate(update.chat_id, update.max_date, update.date, 1);
@ -4426,7 +4494,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter
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);
messageData = Utilities.aesIgeEncryption(messageData, keyData.aesKey, keyData.aesIv, false, false, 0);
is = new SerializedData(messageData);
int len = is.readInt32();

View File

@ -8,15 +8,15 @@
package org.telegram.messenger;
import android.content.Context;
import android.content.SharedPreferences;
import android.text.Html;
import android.util.SparseArray;
import org.telegram.PhoneFormat.PhoneFormat;
import org.telegram.SQLite.SQLiteCursor;
import org.telegram.SQLite.SQLiteDatabase;
import org.telegram.SQLite.SQLitePreparedStatement;
import org.telegram.TL.TLClassStore;
import org.telegram.TL.TLObject;
import org.telegram.TL.TLRPC;
import org.telegram.ui.ApplicationLoader;
import java.io.File;
@ -40,6 +40,8 @@ public class MessagesStorage {
public static final int wallpapersDidLoaded = 171;
public static MessagesStorage Instance = new MessagesStorage();
private boolean appliedDialogFix = false;
public MessagesStorage() {
storageQueue.setPriority(Thread.MAX_PRIORITY);
openDatabase();
@ -48,10 +50,22 @@ public class MessagesStorage {
public void openDatabase() {
cacheFile = new File(ApplicationLoader.applicationContext.getFilesDir(), "cache4.db");
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("dbconfig", Context.MODE_PRIVATE);
appliedDialogFix = preferences.getBoolean("appliedDialogFix", false);
boolean createTable = false;
//cacheFile.delete();
if (!cacheFile.exists()) {
createTable = true;
try {
SharedPreferences.Editor editor = preferences.edit();
editor.putBoolean("appliedDialogFix", true);
appliedDialogFix = true;
editor.commit();
} catch (Exception e) {
FileLog.e("tmessages", e);
}
}
try {
database = new SQLiteDatabase(cacheFile.getPath());
@ -187,6 +201,45 @@ public class MessagesStorage {
});
}
public void applyDialogsFix() { //server bug on 20.02.2014
if (!appliedDialogFix) {
try {
SQLiteCursor cursor = database.queryFinalized("SELECT d.did, m.data FROM dialogs as d LEFT JOIN messages as m ON d.last_mid = m.mid WHERE m.mid < 0 AND m.date >= 1392930900 AND m.date <= 1392935700");
String dids = "";
while (cursor.next()) {
long did = cursor.longValue(0);
byte[] messageData = cursor.byteArrayValue(1);
if (messageData != null) {
SerializedData data = new SerializedData(messageData);
TLRPC.Message message = (TLRPC.Message)TLClassStore.Instance().TLdeserialize(data, data.readInt32());
if (message != null) {
if (message.action != null && message.action instanceof TLRPC.TL_messageActionUserJoined) {
if (dids.length() != 0) {
dids += ",";
}
dids += "" + did;
}
}
}
}
cursor.dispose();
if (dids.length() != 0) {
database.executeFast("DELETE FROM dialogs WHERE did IN(" + dids + ")").stepThis().dispose();
}
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("dbconfig", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = preferences.edit();
editor.putBoolean("appliedDialogFix", true);
appliedDialogFix = true;
editor.commit();
} catch (Exception e) {
FileLog.e("tmessages", e);
}
}
}
public void saveSecretParams(final int lsv, final int sg, final byte[] pbytes) {
storageQueue.postRunnable(new Runnable() {
@Override
@ -464,7 +517,7 @@ public class MessagesStorage {
}
state.dispose();
database.commitTransaction();
database.executeFast(String.format(Locale.US, "UPDATE messages SET ttl = 0 WHERE mid IN (%s)", mids)).stepThis().dispose();
database.executeFast(String.format(Locale.US, "UPDATE messages SET ttl = 0 WHERE mid IN(%s)", mids)).stepThis().dispose();
MessagesController.Instance.didAddedNewTask(minDate);
}
} catch (Exception e) {
@ -474,7 +527,7 @@ public class MessagesStorage {
});
}
private void updateDialogsWithReadedMessagesInternal(final ArrayList<Integer> messages/*, final HashMap<Integer, Integer> encryptedMessages*/) {
private void updateDialogsWithReadedMessagesInternal(final ArrayList<Integer> messages) {
if (Thread.currentThread().getId() != storageQueue.getId()) {
throw new RuntimeException("wrong db thread");
}
@ -489,182 +542,57 @@ public class MessagesStorage {
}
ids += uid;
}
SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT uid FROM messages WHERE mid IN(%s) AND out = 0", ids));
SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT uid, read_state, out FROM messages WHERE mid IN(%s)", ids));
while (cursor.next()) {
int out = cursor.intValue(2);
if (out != 0) {
continue;
}
int read_state = cursor.intValue(1);
if (read_state != 0) {
continue;
}
long uid = cursor.longValue(0);
Integer currentCount = dialogsToUpdate.get(uid);
if (currentCount == null) {
dialogsToUpdate.put(uid, 1);
if (dialogsToReload.length() != 0) {
dialogsToReload += ",";
}
dialogsToReload += uid;
} else {
dialogsToUpdate.put(uid, currentCount + 1);
}
}
cursor.dispose();
cursor = database.queryFinalized(String.format(Locale.US, "SELECT did, unread_count FROM dialogs WHERE did IN(%s)", dialogsToReload));
while (cursor.next()) {
long did = cursor.longValue(0);
int count = cursor.intValue(1);
Integer currentCount = dialogsToUpdate.get(did);
if (currentCount != null) {
dialogsToUpdate.put(did, Math.max(0, count - currentCount));
} else {
dialogsToUpdate.remove(did);
}
}
cursor.dispose();
database.beginTransaction();
SQLitePreparedStatement state = database.executeFast("UPDATE dialogs SET unread_count = max(0, (SELECT unread_count FROM dialogs WHERE did = ?) - ?) WHERE did = ?");
SQLitePreparedStatement state = database.executeFast("UPDATE dialogs SET unread_count = ? WHERE did = ?");
for (HashMap.Entry<Long, Integer> entry : dialogsToUpdate.entrySet()) {
state.requery();
state.bindLong(1, entry.getKey());
state.bindInteger(2, entry.getValue());
state.bindLong(3, entry.getKey());
state.bindInteger(1, entry.getValue());
state.bindLong(2, entry.getKey());
state.step();
if (dialogsToReload.length() != 0) {
dialogsToReload += ",";
}
dialogsToReload += entry.getKey();
}
state.dispose();
database.commitTransaction();
}
/*if (encryptedMessages != null && !encryptedMessages.isEmpty()) {
database.beginTransaction();
SQLitePreparedStatement state = database.executeFast("UPDATE dialogs SET unread_count = (SELECT COUNT(uid) FROM messages WHERE did = ? AND read_state = 0 AND out = 0) WHERE did = ?");
for (HashMap.Entry<Integer, Integer> entry : encryptedMessages.entrySet()) {
long dialog_id = ((long)entry.getKey()) << 32;
state.requery();
state.bindLong(1, dialog_id);
state.bindLong(2, dialog_id);
state.step();
if (dialogsToReload.length() != 0) {
dialogsToReload += ",";
}
dialogsToReload += dialog_id;
}
state.dispose();
database.commitTransaction();
}*/
TLRPC.messages_Dialogs dialogs = new TLRPC.messages_Dialogs();
ArrayList<TLRPC.EncryptedChat> encryptedChats = new ArrayList<TLRPC.EncryptedChat>();
ArrayList<Integer> usersToLoad = new ArrayList<Integer>();
ArrayList<Integer> chatsToLoad = new ArrayList<Integer>();
ArrayList<Integer> encryptedToLoad = new ArrayList<Integer>();
SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT d.did, d.last_mid, d.unread_count, d.date, m.data, m.read_state, m.mid, m.send_state FROM dialogs as d LEFT JOIN messages as m ON d.last_mid = m.mid WHERE d.did IN(%s)", dialogsToReload));
while (cursor.next()) {
TLRPC.TL_dialog dialog = new TLRPC.TL_dialog();
dialog.id = cursor.longValue(0);
dialog.top_message = cursor.intValue(1);
dialog.unread_count = cursor.intValue(2);
dialog.last_message_date = cursor.intValue(3);
dialogs.dialogs.add(dialog);
byte[] messageData = cursor.byteArrayValue(4);
if (messageData != null) {
SerializedData data = new SerializedData(messageData);
TLRPC.Message message = (TLRPC.Message)TLClassStore.Instance().TLdeserialize(data, data.readInt32());
message.unread = (cursor.intValue(5) != 1);
message.id = cursor.intValue(6);
message.send_state = cursor.intValue(7);
dialogs.messages.add(message);
if (!usersToLoad.contains(message.from_id)) {
usersToLoad.add(message.from_id);
}
if (message.action != null && message.action.user_id != 0) {
if (!usersToLoad.contains(message.action.user_id)) {
usersToLoad.add(message.action.user_id);
}
}
if (message.fwd_from_id != 0) {
if (!usersToLoad.contains(message.fwd_from_id)) {
usersToLoad.add(message.fwd_from_id);
}
}
}
int lower_id = (int)dialog.id;
if (lower_id != 0) {
if (lower_id > 0) {
if (!usersToLoad.contains(lower_id)) {
usersToLoad.add(lower_id);
}
} else {
if (!chatsToLoad.contains(-lower_id)) {
chatsToLoad.add(-lower_id);
}
}
} else {
int encryptedId = (int)(dialog.id >> 32);
if (!encryptedToLoad.contains(encryptedId)) {
encryptedToLoad.add(encryptedId);
}
}
}
cursor.dispose();
if (!encryptedToLoad.isEmpty()) {
String toLoad = "";
for (int uid : encryptedToLoad) {
if (toLoad.length() != 0) {
toLoad += ",";
}
toLoad += uid;
}
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);
TLRPC.EncryptedChat chat = (TLRPC.EncryptedChat)TLClassStore.Instance().TLdeserialize(data, data.readInt32());
encryptedChats.add(chat);
chat.user_id = cursor.intValue(1);
if (!usersToLoad.contains(chat.user_id)) {
usersToLoad.add(chat.user_id);
}
chat.a_or_b = cursor.byteArrayValue(2);
chat.auth_key = cursor.byteArrayValue(3);
chat.ttl = cursor.intValue(4);
}
}
cursor.dispose();
}
if (!chatsToLoad.isEmpty()) {
String toLoad = "";
for (int uid : chatsToLoad) {
if (toLoad.length() != 0) {
toLoad += ",";
}
toLoad += uid;
}
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);
TLRPC.Chat chat = (TLRPC.Chat)TLClassStore.Instance().TLdeserialize(data, data.readInt32());
dialogs.chats.add(chat);
}
}
cursor.dispose();
}
if (!usersToLoad.isEmpty()) {
String toLoad = "";
for (int uid : usersToLoad) {
if (toLoad.length() != 0) {
toLoad += ",";
}
toLoad += uid;
}
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);
TLRPC.User user = (TLRPC.User)TLClassStore.Instance().TLdeserialize(data, data.readInt32());
if (user.status != null) {
user.status.was_online = user.status.expires = cursor.intValue(1);
}
dialogs.users.add(user);
}
}
cursor.dispose();
}
if (!dialogs.dialogs.isEmpty() || !encryptedChats.isEmpty()) {
MessagesController.Instance.processDialogsUpdate(dialogs, encryptedChats);
if (!dialogsToUpdate.isEmpty()) {
MessagesController.Instance.processDialogsUpdateRead(dialogsToUpdate);
}
} catch (Exception e) {
FileLog.e("tmessages", e);
@ -808,7 +736,7 @@ public class MessagesStorage {
TLRPC.User user = (TLRPC.User)TLClassStore.Instance().TLdeserialize(data, data.readInt32());
loadedUsers.add(user);
if (user.status != null) {
user.status.was_online = user.status.expires = cursor.intValue(1);
user.status.expires = cursor.intValue(1);
}
}
}
@ -900,7 +828,7 @@ public class MessagesStorage {
continue;
}
if (user.status != null) {
user.status.was_online = user.status.expires = cursor.intValue(1);
user.status.expires = cursor.intValue(1);
}
resultArrayNames.add(Utilities.generateSearchName(user.first_name, user.last_name, q));
resultArray.add(user);
@ -931,7 +859,7 @@ public class MessagesStorage {
SerializedData data2 = new SerializedData(userData);
TLRPC.User user = (TLRPC.User)TLClassStore.Instance().TLdeserialize(data2, data2.readInt32());
if (user.status != null) {
user.status.was_online = user.status.expires = cursor.intValue(7);
user.status.expires = cursor.intValue(7);
}
resultArrayNames.add(Html.fromHtml("<font color=\"#00a60e\">" + Utilities.formatName(user.first_name, user.last_name) + "</font>"));
resultArray.add(chat);
@ -1013,7 +941,7 @@ public class MessagesStorage {
}
ids += "" + uid;
}
database.executeFast("DELETE FROM contacts WHERE uid IN (" + ids + ")").stepThis().dispose();
database.executeFast("DELETE FROM contacts WHERE uid IN(" + ids + ")").stepThis().dispose();
} catch (Exception e) {
FileLog.e("tmessages", e);
}
@ -1030,10 +958,10 @@ public class MessagesStorage {
public void run() {
try {
if (adds.length() != 0) {
database.executeFast(String.format(Locale.US, "UPDATE user_phones_v6 SET deleted = 0 WHERE sphone IN (%s)", adds)).stepThis().dispose();
database.executeFast(String.format(Locale.US, "UPDATE user_phones_v6 SET deleted = 0 WHERE sphone IN(%s)", adds)).stepThis().dispose();
}
if (deletes.length() != 0) {
database.executeFast(String.format(Locale.US, "UPDATE user_phones_v6 SET deleted = 1 WHERE sphone IN (%s)", deletes)).stepThis().dispose();
database.executeFast(String.format(Locale.US, "UPDATE user_phones_v6 SET deleted = 1 WHERE sphone IN(%s)", deletes)).stepThis().dispose();
}
} catch (Exception e) {
FileLog.e("tmessages", e);
@ -1054,6 +982,9 @@ public class MessagesStorage {
SQLitePreparedStatement state2 = database.executeFast("REPLACE INTO user_phones_v6 VALUES(?, ?, ?, ?)");
for (HashMap.Entry<Integer, ContactsController.Contact> entry : contactHashMap.entrySet()) {
ContactsController.Contact contact = entry.getValue();
if (contact.phones.isEmpty() || contact.shortPhones.isEmpty()) {
continue;
}
state.requery();
state.bindInteger(1, contact.id);
state.bindString(2, contact.first_name);
@ -1095,8 +1026,19 @@ public class MessagesStorage {
contact.id = uid;
contactHashMap.put(uid, contact);
}
contact.phones.add(cursor.stringValue(3));
contact.shortPhones.add(cursor.stringValue(4));
String phone = cursor.stringValue(3);
if (phone == null) {
continue;
}
contact.phones.add(phone);
String sphone = cursor.stringValue(4);
if (sphone == null) {
continue;
}
if (sphone.length() == 8 && phone.length() != 8) {
sphone = PhoneFormat.stripExceptNumbers(phone);
}
contact.shortPhones.add(sphone);
contact.phoneDeleted.add(cursor.intValue(5));
contact.phoneTypes.add("");
}
@ -1105,7 +1047,7 @@ public class MessagesStorage {
contactHashMap.clear();
FileLog.e("tmessages", e);
}
ContactsController.Instance.performSyncPhoneBook(contactHashMap, true, true);
ContactsController.Instance.performSyncPhoneBook(contactHashMap, true, true, false);
}
});
}
@ -1144,7 +1086,7 @@ public class MessagesStorage {
TLRPC.User user = (TLRPC.User)TLClassStore.Instance().TLdeserialize(data, data.readInt32());
users.add(user);
if (user.status != null) {
user.status.was_online = user.status.expires = cursor.intValue(1);
user.status.expires = cursor.intValue(1);
}
}
}
@ -1265,7 +1207,7 @@ public class MessagesStorage {
TLRPC.User user = (TLRPC.User)TLClassStore.Instance().TLdeserialize(data, data.readInt32());
loadedUsers.add(user.id);
if (user.status != null) {
user.status.was_online = user.status.expires = cursor.intValue(1);
user.status.expires = cursor.intValue(1);
}
res.users.add(user);
}
@ -1425,6 +1367,9 @@ public class MessagesStorage {
if (message.media != null && message.media.user_id != 0) {
fromUser.add(message.media.user_id);
}
if (message.media != null && message.media.audio != null && message.media.audio.user_id != 0) {
fromUser.add(message.media.audio.user_id);
}
if (message.fwd_from_id != 0) {
fromUser.add(message.fwd_from_id);
}
@ -1455,7 +1400,7 @@ public class MessagesStorage {
TLRPC.User user = (TLRPC.User)TLClassStore.Instance().TLdeserialize(data, data.readInt32());
loadedUsers.add(user.id);
if (user.status != null) {
user.status.was_online = user.status.expires = cursor.intValue(1);
user.status.expires = cursor.intValue(1);
}
res.users.add(user);
}
@ -1601,7 +1546,7 @@ public class MessagesStorage {
SerializedData data = new SerializedData(userData);
TLRPC.User user = (TLRPC.User)TLClassStore.Instance().TLdeserialize(data, data.readInt32());
if (user.status != null) {
user.status.was_online = user.status.expires = cursor.intValue(1);
user.status.expires = cursor.intValue(1);
}
result.add(user);
}
@ -1693,7 +1638,7 @@ public class MessagesStorage {
state.bindString(2, "");
}
if (user.status != null) {
state.bindInteger(3, (user.status.was_online != 0 ? user.status.was_online : user.status.expires));
state.bindInteger(3, user.status.expires);
} else {
state.bindInteger(3, 0);
}
@ -2071,7 +2016,7 @@ public class MessagesStorage {
for (TLRPC.User user : users) {
state.requery();
if (user.status != null) {
state.bindInteger(1, (user.status.was_online != 0 ? user.status.was_online : user.status.expires));
state.bindInteger(1, user.status.expires);
} else {
state.bindInteger(1, 0);
}
@ -2101,7 +2046,7 @@ public class MessagesStorage {
TLRPC.User user = (TLRPC.User)TLClassStore.Instance().TLdeserialize(data, data.readInt32());
loadedUsers.add(user);
if (user.status != null) {
user.status.was_online = user.status.expires = cursor.intValue(1);
user.status.expires = cursor.intValue(1);
}
TLRPC.User updateUser = usersDict.get(user.id);
if (updateUser.first_name != null && updateUser.last_name != null) {
@ -2130,7 +2075,7 @@ public class MessagesStorage {
state.bindString(2, "");
}
if (user.status != null) {
state.bindInteger(3, (user.status.was_online != 0 ? user.status.was_online : user.status.expires));
state.bindInteger(3, user.status.expires);
} else {
state.bindInteger(3, 0);
}
@ -2177,7 +2122,7 @@ public class MessagesStorage {
}
ids += uid;
}
database.executeFast(String.format(Locale.US, "UPDATE messages SET read_state = 1 WHERE mid IN (%s)", ids)).stepThis().dispose();
database.executeFast(String.format(Locale.US, "UPDATE messages SET read_state = 1 WHERE mid IN(%s)", ids)).stepThis().dispose();
}
if (encryptedMessages != null && !encryptedMessages.isEmpty()) {
for (HashMap.Entry<Integer, Integer> entry : encryptedMessages.entrySet()) {
@ -2221,8 +2166,8 @@ public class MessagesStorage {
}
ids += uid;
}
database.executeFast(String.format(Locale.US, "DELETE FROM messages WHERE mid IN (%s)", ids)).stepThis().dispose();
database.executeFast(String.format(Locale.US, "DELETE FROM media WHERE mid IN (%s)", ids)).stepThis().dispose();
database.executeFast(String.format(Locale.US, "DELETE FROM messages WHERE mid IN(%s)", ids)).stepThis().dispose();
database.executeFast(String.format(Locale.US, "DELETE FROM media WHERE mid IN(%s)", ids)).stepThis().dispose();
database.executeFast("DELETE FROM media_counts WHERE 1").stepThis().dispose();
} catch (Exception e) {
@ -2388,7 +2333,7 @@ public class MessagesStorage {
SerializedData data = new SerializedData(userData);
TLRPC.User user = (TLRPC.User)TLClassStore.Instance().TLdeserialize(data, data.readInt32());
if (user.status != null) {
user.status.was_online = user.status.expires = cursor.intValue(1);
user.status.expires = cursor.intValue(1);
}
dialogs.users.add(user);
}
@ -2489,7 +2434,7 @@ public class MessagesStorage {
state.bindString(2, "");
}
if (user.status != null) {
state.bindInteger(3, (user.status.was_online != 0 ? user.status.was_online : user.status.expires));
state.bindInteger(3, user.status.expires);
} else {
state.bindInteger(3, 0);
}
@ -2667,7 +2612,7 @@ public class MessagesStorage {
TLRPC.User user = (TLRPC.User)TLClassStore.Instance().TLdeserialize(data, data.readInt32());
if (user != null) {
if (user.status != null) {
user.status.was_online = user.status.expires = cursor.intValue(1);
user.status.expires = cursor.intValue(1);
}
dialogs.users.add(user);
}
@ -2771,7 +2716,7 @@ public class MessagesStorage {
state.bindString(2, "");
}
if (user.status != null) {
state.bindInteger(3, (user.status.was_online != 0 ? user.status.was_online : user.status.expires));
state.bindInteger(3, user.status.expires);
} else {
state.bindInteger(3, 0);
}

View File

@ -8,8 +8,6 @@
package org.telegram.messenger;
import org.telegram.TL.TLRPC;
public class NetworkMessage {
public TLRPC.TL_protoMessage protoMessage;
public Object rawRequest;

View File

@ -8,9 +8,6 @@
package org.telegram.messenger;
import org.telegram.TL.TLObject;
import org.telegram.TL.TLRPC;
import java.util.ArrayList;
public class RPCRequest {

View File

@ -14,9 +14,8 @@ import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class SerializedData {
public class SerializedData extends AbsSerializedData {
protected boolean isOut = true;
private ByteArrayOutputStream outbuf;
private DataOutputStream out;
@ -44,13 +43,13 @@ public class SerializedData {
out = new DataOutputStream(outbuf);
}
public SerializedData(byte[] data){
public SerializedData(byte[] data) {
isOut = false;
inbuf = new ByteArrayInputStream(data);
in = new DataInputStream(inbuf);
}
public SerializedData(File file) throws IOException {
public SerializedData(File file) throws Exception {
FileInputStream is = new FileInputStream(file);
byte[] data = new byte[(int)file.length()];
new DataInputStream(is).readFully(data);
@ -74,7 +73,7 @@ public class SerializedData {
for(int i = 0; i < 4; i++) {
out.write(x >> (i * 8));
}
} catch(IOException gfdsgd) {
} catch(Exception e) {
FileLog.e("tmessages", "write int32 error");
}
}
@ -89,10 +88,10 @@ public class SerializedData {
private void writeInt64(long x, DataOutputStream out) {
try {
for(int i = 0; i < 8; i++){
for(int i = 0; i < 8; i++) {
out.write((int)(x >> (i * 8)));
}
} catch(IOException gfdsgd) {
} catch(Exception e) {
FileLog.e("tmessages", "write int64 error");
}
}
@ -127,14 +126,14 @@ public class SerializedData {
public int readInt32(boolean[] error) {
try {
int i = 0;
for(int j = 0; j < 4; j++){
for(int j = 0; j < 4; j++) {
i |= (in.read() << (j * 8));
}
if (error != null) {
error[0] = false;
}
return i;
} catch(IOException x) {
} catch(Exception x) {
if (error != null) {
error[0] = true;
}
@ -150,14 +149,14 @@ public class SerializedData {
public long readInt64(boolean[] error) {
try {
long i = 0;
for(int j = 0; j < 8; j++){
for(int j = 0; j < 8; j++) {
i |= ((long)in.read() << (j * 8));
}
if (error != null) {
error[0] = false;
}
return i;
} catch(IOException x) {
} catch (Exception x) {
if (error != null) {
error[0] = true;
}
@ -173,7 +172,7 @@ public class SerializedData {
} else {
len += b.length;
}
} catch(Exception x) {
} catch (Exception x) {
FileLog.e("tmessages", "write raw error");
}
}
@ -185,7 +184,7 @@ public class SerializedData {
} else {
len += count;
}
} catch(Exception x) {
} catch (Exception x) {
FileLog.e("tmessages", "write raw error");
}
}
@ -217,7 +216,7 @@ public class SerializedData {
public void readRaw(byte[] b) {
try {
in.read(b);
} catch(Exception x) {
} catch (Exception x) {
FileLog.e("tmessages", "read raw error");
}
}
@ -232,7 +231,7 @@ public class SerializedData {
try {
int sl = 1;
int l = in.read();
if(l >= 254){
if(l >= 254) {
l = in.read() | (in.read() << 8) | (in.read() << 16);
sl = 4;
}
@ -244,7 +243,7 @@ public class SerializedData {
i++;
}
return new String(b, "UTF-8");
} catch(Exception x) {
} catch (Exception x) {
FileLog.e("tmessages", "read string error");
}
return null;
@ -254,27 +253,31 @@ public class SerializedData {
try {
int sl = 1;
int l = in.read();
if (l >= 254){
if (l >= 254) {
l = in.read() | (in.read() << 8) | (in.read() << 16);
sl = 4;
}
byte[] b = new byte[l];
in.read(b);
int i = sl;
while((l + i) % 4 != 0){
while((l + i) % 4 != 0) {
in.read();
i++;
}
return b;
} catch(Exception x) {
} catch (Exception x) {
FileLog.e("tmessages", "read byte array error");
}
return null;
}
public ByteBufferDesc readByteBuffer() {
throw new RuntimeException("SerializedData don't support readByteBuffer");
}
public void writeByteArray(byte[] b) {
try {
if (b.length <= 253){
if (b.length <= 253) {
if (!justCalc) {
out.write(b.length);
} else {
@ -296,7 +299,7 @@ public class SerializedData {
len += b.length;
}
int i = b.length <= 253 ? 1 : 4;
while((b.length + i) % 4 != 0){
while((b.length + i) % 4 != 0) {
if (!justCalc) {
out.write(0);
} else {
@ -304,12 +307,12 @@ public class SerializedData {
}
i++;
}
} catch(Exception x) {
} catch (Exception x) {
FileLog.e("tmessages", "write byte array error");
}
}
public void writeString(String s){
public void writeString(String s) {
try {
writeByteArray(s.getBytes("UTF-8"));
} catch(Exception x) {
@ -319,7 +322,7 @@ public class SerializedData {
public void writeByteArray(byte[] b, int offset, int count) {
try {
if(count <= 253){
if(count <= 253) {
if (!justCalc) {
out.write(count);
} else {
@ -341,7 +344,7 @@ public class SerializedData {
len += count;
}
int i = count <= 253 ? 1 : 4;
while ((count + i) % 4 != 0){
while ((count + i) % 4 != 0) {
if (!justCalc) {
out.write(0);
} else {
@ -349,7 +352,7 @@ public class SerializedData {
}
i++;
}
} catch(Exception x) {
} catch (Exception x) {
FileLog.e("tmessages", "write byte array error");
}
}

View File

@ -6,10 +6,7 @@
* Copyright Nikolai Kudashov, 2013.
*/
package org.telegram.TL;
import org.telegram.messenger.FileLog;
import org.telegram.messenger.SerializedData;
package org.telegram.messenger;
import java.util.HashMap;
@ -317,6 +314,7 @@ public class TLClassStore {
classStore.put(TLRPC.TL_req_DH_params.constructor, TLRPC.TL_req_DH_params.class);
classStore.put(TLRPC.TL_set_client_DH_params.constructor, TLRPC.TL_set_client_DH_params.class);
classStore.put(TLRPC.TL_ping.constructor, TLRPC.TL_ping.class);
classStore.put(TLRPC.TL_ping_delay_disconnect.constructor, TLRPC.TL_ping_delay_disconnect.class);
classStore.put(TLRPC.TL_destroy_session.constructor, TLRPC.TL_destroy_session.class);
classStore.put(TLRPC.TL_destroy_sessions.constructor, TLRPC.TL_destroy_sessions.class);
classStore.put(TLRPC.TL_get_future_salts.constructor, TLRPC.TL_get_future_salts.class);
@ -408,6 +406,8 @@ public class TLClassStore {
classStore.put(TLRPC.TL_messages_sendEncryptedService.constructor, TLRPC.TL_messages_sendEncryptedService.class);
classStore.put(TLRPC.TL_messages_receivedQueue.constructor, TLRPC.TL_messages_receivedQueue.class);
classStore.put(TLRPC.TL_upload_saveBigFilePart.constructor, TLRPC.TL_upload_saveBigFilePart.class);
classStore.put(TLRPC.TL_help_support.constructor, TLRPC.TL_help_support.class);
classStore.put(TLRPC.TL_help_getSupport.constructor, TLRPC.TL_help_getSupport.class);
classStore.put(TLRPC.TL_msg_container.constructor, TLRPC.TL_msg_container.class);
classStore.put(TLRPC.TL_fileEncryptedLocation.constructor, TLRPC.TL_fileEncryptedLocation.class);
@ -434,7 +434,7 @@ public class TLClassStore {
return store;
}
public TLObject TLdeserialize(SerializedData stream, int constructor) {
public TLObject TLdeserialize(AbsSerializedData stream, int constructor) {
try {
return TLdeserialize(stream, constructor, null);
} catch (Exception e) {
@ -442,7 +442,7 @@ public class TLClassStore {
}
}
public TLObject TLdeserialize(SerializedData stream, int constructor, TLObject request) {
public TLObject TLdeserialize(AbsSerializedData stream, int constructor, TLObject request) {
Class objClass = classStore.get(constructor);
if (objClass != null) {
try {

View File

@ -6,16 +6,14 @@
* Copyright Nikolai Kudashov, 2013.
*/
package org.telegram.TL;
import org.telegram.messenger.SerializedData;
package org.telegram.messenger;
public class TLObject {
public TLObject () {
}
public void readParams(SerializedData stream) {
public void readParams(AbsSerializedData stream) {
}
@ -23,7 +21,7 @@ public class TLObject {
return null;
}
public void serializeToStream(SerializedData stream) {
public void serializeToStream(AbsSerializedData stream) {
}
@ -35,7 +33,11 @@ public class TLObject {
return 11;
}
public void parseVector(TLRPC.Vector vector, SerializedData data) {
public void parseVector(TLRPC.Vector vector, AbsSerializedData data) {
}
public void freeResources() {
}
}

View File

@ -33,7 +33,7 @@ public class TcpConnection extends PyroClientAdapter {
public abstract void tcpConnectionClosed(TcpConnection connection);
public abstract void tcpConnectionConnected(TcpConnection connection);
public abstract void tcpConnectionQuiackAckReceived(TcpConnection connection, int ack);
public abstract void tcpConnectionReceivedData(TcpConnection connection, byte[] data);
public abstract void tcpConnectionReceivedData(TcpConnection connection, ByteBufferDesc data, int length);
public abstract void tcpConnectionProgressChanged(TcpConnection connection, long messageId, int currentSize, int length);
}
@ -46,13 +46,14 @@ public class TcpConnection extends PyroClientAdapter {
private int datacenterId;
private int failedConnectionCount;
public TcpConnectionDelegate delegate;
private ByteBuffer restOfTheData;
private ByteBufferDesc restOfTheData;
private long lastMessageId = 0;
private boolean hasSomeDataSinceLastConnect = false;
private int willRetryConnectCount = 5;
private boolean isNextPort = false;
private final Integer timerSync = 1;
private boolean wasConnected;
private int lastPacketLength;
public int transportRequestClass;
@ -64,6 +65,7 @@ public class TcpConnection extends PyroClientAdapter {
if (selector == null) {
selector = new PyroSelector();
selector.spawnNetworkThread("network thread");
BuffersStorage storage = BuffersStorage.Instance;
}
datacenterId = did;
connectionState = TcpConnectionState.TcpConnectionStageIdle;
@ -103,7 +105,11 @@ public class TcpConnection extends PyroClientAdapter {
hostPort = datacenter.getCurrentPort();
FileLog.d("tmessages", String.format(TcpConnection.this + " Connecting (%s:%d)", hostAddress, hostPort));
firstPacket = true;
restOfTheData = null;
if (restOfTheData != null) {
BuffersStorage.Instance.reuseFreeBuffer(restOfTheData);
restOfTheData = null;
}
lastPacketLength = 0;
wasConnected = false;
hasSomeDataSinceLastConnect = false;
if (client != null) {
@ -218,7 +224,11 @@ public class TcpConnection extends PyroClientAdapter {
});
}
firstPacket = true;
restOfTheData = null;
if (restOfTheData != null) {
BuffersStorage.Instance.reuseFreeBuffer(restOfTheData);
restOfTheData = null;
}
lastPacketLength = 0;
channelToken = 0;
wasConnected = false;
}
@ -294,15 +304,71 @@ public class TcpConnection extends PyroClientAdapter {
}
private void readData(ByteBuffer buffer) throws Exception {
buffer.order(ByteOrder.LITTLE_ENDIAN);
buffer.rewind();
ByteBuffer parseLaterBuffer = null;
if (restOfTheData != null) {
ByteBuffer newBuffer = ByteBuffer.allocate(restOfTheData.limit() + buffer.limit());
newBuffer.put(restOfTheData);
newBuffer.put(buffer);
buffer = newBuffer;
restOfTheData = null;
if (lastPacketLength == 0) {
//FileLog.e("tmessages", this + " write addition data to restOfTheData");
if (restOfTheData.capacity() - restOfTheData.position() >= buffer.limit()) {
restOfTheData.limit(restOfTheData.position() + buffer.limit());
restOfTheData.put(buffer);
buffer = restOfTheData.buffer;
//FileLog.e("tmessages", this + " no need to recreate buffer");
} else {
ByteBufferDesc newBuffer = BuffersStorage.Instance.getFreeBuffer(restOfTheData.limit() + buffer.limit());
restOfTheData.rewind();
newBuffer.put(restOfTheData.buffer);
newBuffer.put(buffer);
buffer = newBuffer.buffer;
BuffersStorage.Instance.reuseFreeBuffer(restOfTheData);
restOfTheData = newBuffer;
//FileLog.e("tmessages", this + " NEED to recreate buffer");
}
} else {
//FileLog.e("tmessages", this + " write buffer to restOfTheData buffer of len = " + lastPacketLength);
int len = 0;
if (lastPacketLength - restOfTheData.position() <= buffer.limit()) {
len = lastPacketLength - restOfTheData.position();
//FileLog.e("tmessages", this + " received buffer - OK!");
} else {
len = buffer.limit();
//FileLog.e("tmessages", this + " received buffer less than need");
}
int oldLimit = buffer.limit();
buffer.limit(len);
restOfTheData.put(buffer);
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!");
if (buffer.hasRemaining()) {
parseLaterBuffer = buffer;
//FileLog.e("tmessages", this + " something remain in the received buffer");
} else {
parseLaterBuffer = null;
}
buffer = restOfTheData.buffer;
}
}
}
buffer.order(ByteOrder.LITTLE_ENDIAN);
buffer.rewind();
while (buffer.hasRemaining()) {
@ -310,7 +376,7 @@ public class TcpConnection extends PyroClientAdapter {
Datacenter datacenter = ConnectionsManager.Instance.datacenterWithId(datacenterId);
datacenter.storeCurrentAddressAndPortNum();
isNextPort = false;
client.setTimeout(20000);
client.setTimeout(25000);
}
hasSomeDataSinceLastConnect = true;
@ -321,9 +387,16 @@ public class TcpConnection extends PyroClientAdapter {
if ((fByte & (1 << 7)) != 0) {
buffer.reset();
if (buffer.remaining() < 4) {
restOfTheData = ByteBuffer.allocate(buffer.remaining());
ByteBufferDesc reuseLater = restOfTheData;
restOfTheData = BuffersStorage.Instance.getFreeBuffer(16384);
restOfTheData.put(buffer);
restOfTheData.rewind();
restOfTheData.limit(restOfTheData.position());
lastPacketLength = 0;
//FileLog.e("tmessages", this + " 1 - size less than 4 bytes - write to free buffer");
if (reuseLater != null) {
BuffersStorage.Instance.reuseFreeBuffer(reuseLater);
//FileLog.e("tmessages", this + " 1 - reuse later buffer1");
}
break;
}
buffer.order(ByteOrder.BIG_ENDIAN);
@ -346,16 +419,27 @@ public class TcpConnection extends PyroClientAdapter {
} else {
buffer.reset();
if (buffer.remaining() < 4) {
restOfTheData = ByteBuffer.allocate(buffer.remaining());
restOfTheData.put(buffer);
restOfTheData.rewind();
//FileLog.e("tmessages", this + " 2 - size less than 4 bytes - write to free buffer");
if (restOfTheData == null || restOfTheData != null && restOfTheData.position() != 0) {
ByteBufferDesc reuseLater = restOfTheData;
restOfTheData = BuffersStorage.Instance.getFreeBuffer(16384);
restOfTheData.put(buffer);
restOfTheData.limit(restOfTheData.position());
lastPacketLength = 0;
if (reuseLater != null) {
BuffersStorage.Instance.reuseFreeBuffer(reuseLater);
//FileLog.e("tmessages", this + " 2 - reuse later buffer1");
}
} else {
restOfTheData.position(restOfTheData.limit());
}
break;
}
currentPacketLength = (buffer.getInt() >> 8) * 4;
}
if (currentPacketLength % 4 != 0 || currentPacketLength > 2 * 1024 * 1024) {
FileLog.e("tmessages", "Invalid packet length");
//FileLog.e("tmessages", "Invalid packet length");
reconnect();
return;
}
@ -388,26 +472,68 @@ public class TcpConnection extends PyroClientAdapter {
}
}
}
buffer.reset();
restOfTheData = ByteBuffer.allocate(buffer.remaining());
restOfTheData.order(ByteOrder.LITTLE_ENDIAN);
restOfTheData.put(buffer);
restOfTheData.rewind();
ByteBufferDesc reuseLater = null;
int len = currentPacketLength + (fByte != 0x7f ? 1 : 4);
if (restOfTheData != null && restOfTheData.capacity() < len) {
reuseLater = restOfTheData;
restOfTheData = null;
//FileLog.e("tmessages", this + " not enough space for len, recreate buffer = " + len);
}
if (restOfTheData == null) {
//FileLog.e("tmessages", this + " write to restOfTheData, get buffer len = " + len);
buffer.reset();
restOfTheData = BuffersStorage.Instance.getFreeBuffer(len);
restOfTheData.put(buffer);
} else {
restOfTheData.position(restOfTheData.limit());
restOfTheData.limit(len);
}
lastPacketLength = len;
if (reuseLater != null) {
BuffersStorage.Instance.reuseFreeBuffer(reuseLater);
//FileLog.e("tmessages", this + " 3 - reuse later buffer1");
}
return;
}
final byte[] packetData = new byte[currentPacketLength];
buffer.get(packetData);
final int length = currentPacketLength;
final ByteBufferDesc toProceed = BuffersStorage.Instance.getFreeBuffer(currentPacketLength);
int old = buffer.limit();
buffer.limit(buffer.position() + currentPacketLength);
toProceed.put(buffer);
buffer.limit(old);
toProceed.rewind();
if (delegate != null) {
final TcpConnectionDelegate finalDelegate = delegate;
Utilities.stageQueue.postRunnable(new Runnable() {
@Override
public void run() {
finalDelegate.tcpConnectionReceivedData(TcpConnection.this, packetData);
finalDelegate.tcpConnectionReceivedData(TcpConnection.this, toProceed, length);
BuffersStorage.Instance.reuseFreeBuffer(toProceed);
}
});
}
if (restOfTheData != null) {
if (lastPacketLength != 0 && restOfTheData.position() == lastPacketLength || lastPacketLength == 0 && !restOfTheData.hasRemaining()) {
BuffersStorage.Instance.reuseFreeBuffer(restOfTheData);
restOfTheData = null;
//FileLog.e("tmessages", this + " restOfTheData parsed null it");
} else {
restOfTheData.compact();
restOfTheData.limit(restOfTheData.position());
restOfTheData.position(0);
//FileLog.e("tmessages", this + " restOfTheData NOT parsed, compact");
}
}
if (parseLaterBuffer != null) {
//FileLog.e("tmessages", this + " there is parseLaterBuffer");
buffer = parseLaterBuffer;
parseLaterBuffer = null;
}
}
}
@ -425,8 +551,12 @@ public class TcpConnection extends PyroClientAdapter {
}
boolean switchToNextPort = wasConnected && !hasSomeDataSinceLastConnect && timedout;
firstPacket = true;
restOfTheData = null;
if (restOfTheData != null) {
BuffersStorage.Instance.reuseFreeBuffer(restOfTheData);
restOfTheData = null;
}
channelToken = 0;
lastPacketLength = 0;
wasConnected = false;
if (connectionState != TcpConnectionState.TcpConnectionStageSuspended && connectionState != TcpConnectionState.TcpConnectionStageIdle) {
connectionState = TcpConnectionState.TcpConnectionStageIdle;
@ -527,7 +657,7 @@ public class TcpConnection extends PyroClientAdapter {
failedConnectionCount = 0;
readData(data);
} catch (Exception e) {
FileLog.d("tmessages", "read data error");
FileLog.e("tmessages", e);
reconnect();
}
}

View File

@ -12,8 +12,6 @@ import android.content.Context;
import android.content.SharedPreferences;
import android.util.Base64;
import org.telegram.TL.TLClassStore;
import org.telegram.TL.TLRPC;
import org.telegram.ui.ApplicationLoader;
import java.io.File;
@ -30,6 +28,7 @@ public class UserConfig {
public static String importHash = "";
private final static Integer sync = 1;
public static boolean saveIncomingPhotos = false;
public static int contactsVersion = 1;
public static int getNewMessageId() {
int id;
@ -49,14 +48,15 @@ public class UserConfig {
try {
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("userconfing", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = preferences.edit();
editor.putBoolean("registeredForPush", registeredForPush);
editor.putString("pushString", pushString);
editor.putInt("lastSendMessageId", lastSendMessageId);
editor.putInt("lastLocalId", lastLocalId);
editor.putString("contactsHash", contactsHash);
editor.putString("importHash", importHash);
editor.putBoolean("saveIncomingPhotos", saveIncomingPhotos);
editor.putInt("contactsVersion", contactsVersion);
if (currentUser != null) {
editor.putBoolean("registeredForPush", registeredForPush);
editor.putString("pushString", pushString);
editor.putInt("lastSendMessageId", lastSendMessageId);
editor.putInt("lastLocalId", lastLocalId);
editor.putString("contactsHash", contactsHash);
editor.putString("importHash", importHash);
editor.putBoolean("saveIncomingPhotos", saveIncomingPhotos);
if (withFile) {
SerializedData data = new SerializedData();
currentUser.serializeToStream(data);
@ -66,13 +66,6 @@ public class UserConfig {
editor.putString("user", userString);
}
} else {
editor.putBoolean("registeredForPush", registeredForPush);
editor.putString("pushString", pushString);
editor.putInt("lastSendMessageId", lastSendMessageId);
editor.putInt("lastLocalId", lastLocalId);
editor.putString("contactsHash", contactsHash);
editor.putString("importHash", importHash);
editor.putBoolean("saveIncomingPhotos", saveIncomingPhotos);
editor.remove("user");
}
editor.commit();
@ -107,13 +100,7 @@ public class UserConfig {
contactsHash = data.readString();
importHash = data.readString();
saveIncomingPhotos = data.readBool();
if (currentUser.status != null) {
if (currentUser.status.expires != 0) {
currentUser.status.was_online = currentUser.status.expires;
} else {
currentUser.status.expires = currentUser.status.was_online;
}
}
contactsVersion = 0;
MessagesStorage.lastQtsValue = data.readInt32();
MessagesStorage.lastSecretVersion = data.readInt32();
int val = data.readInt32();
@ -141,6 +128,7 @@ public class UserConfig {
contactsHash = preferences.getString("contactsHash", "");
importHash = preferences.getString("importHash", "");
saveIncomingPhotos = preferences.getBoolean("saveIncomingPhotos", false);
contactsVersion = preferences.getInt("contactsVersion", 0);
}
if (lastLocalId > -210000) {
lastLocalId = -210000;
@ -166,6 +154,7 @@ public class UserConfig {
contactsHash = preferences.getString("contactsHash", "");
importHash = preferences.getString("importHash", "");
saveIncomingPhotos = preferences.getBoolean("saveIncomingPhotos", false);
contactsVersion = preferences.getInt("contactsVersion", 0);
String user = preferences.getString("user", null);
if (user != null) {
byte[] userBytes = Base64.decode(user, Base64.DEFAULT);
@ -193,6 +182,7 @@ public class UserConfig {
importHash = "";
lastLocalId = -210000;
lastSendMessageId = -210000;
contactsVersion = 1;
saveIncomingPhotos = false;
saveConfig(true);
MessagesController.Instance.deleteAllAppAccounts();

View File

@ -15,6 +15,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.graphics.Point;
import android.graphics.Typeface;
import android.net.Uri;
import android.os.Build;
@ -27,11 +28,11 @@ import android.text.SpannableStringBuilder;
import android.text.format.DateFormat;
import android.util.AttributeSet;
import android.util.Base64;
import android.view.Display;
import android.view.View;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import org.telegram.TL.TLClassStore;
import org.telegram.TL.TLObject;
import org.telegram.ui.ApplicationLoader;
import java.io.ByteArrayInputStream;
@ -65,6 +66,7 @@ public class Utilities {
public static Handler applicationHandler;
public static int statusBarHeight = 0;
public static float density = 1;
public static Point displaySize = new Point();
public static boolean isRTL = false;
public static Pattern pattern = Pattern.compile("[0-9]+");
private final static Integer lock = 1;
@ -85,7 +87,8 @@ public class Utilities {
public static DispatchQueue fileUploadQueue = new DispatchQueue("fileUploadQueue");
public native static long doPQNative(long _what);
public native static byte[] aesIgeEncryption(byte[] _what, byte[] _key, byte[] _iv, boolean encrypt, boolean changeIv);
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 static boolean isWaitingForSms() {
boolean value = false;
@ -111,6 +114,14 @@ public class Utilities {
return val;
}
public static String parseIntToString(String value) {
Matcher matcher = pattern.matcher(value);
if (matcher.find()) {
return matcher.group(0);
}
return null;
}
static {
density = ApplicationLoader.applicationContext.getResources().getDisplayMetrics().density;
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("primes", Context.MODE_PRIVATE);
@ -164,6 +175,10 @@ public class Utilities {
return (int)(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;
@ -282,6 +297,23 @@ public class Utilities {
return null;
}
public static byte[] computeSHA1(ByteBuffer convertme, int offset, int len) {
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);
}
return null;
}
public static byte[] computeSHA1(byte[] convertme) {
try {
MessageDigest md = MessageDigest.getInstance("SHA-1");
@ -533,8 +565,28 @@ 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);
}
}
static {
recreateFormatters();
Utilities.checkDisplaySize();
}
public static String formatDateChat(long date) {
@ -678,14 +730,14 @@ public class Utilities {
}
public static int getColorForId(int id) {
if (id == 333000) {
if (id / 1000 == 333) {
return 0xff0f94ed;
}
return arrColors[getColorIndex(id)];
}
public static int getUserAvatarForId(int id) {
if (id == 333000) {
if (id / 1000 == 333) {
return R.drawable.telegram_avatar;
}
return arrUsersAvatars[getColorIndex(id)];
@ -807,9 +859,12 @@ public class Utilities {
final int column_index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(column_index);
}
} catch (Exception e) {
FileLog.e("tmessages", e);
} finally {
if (cursor != null)
if (cursor != null) {
cursor.close();
}
}
return null;
}

View File

@ -9,9 +9,16 @@
package org.telegram.objects;
import android.graphics.Bitmap;
import android.graphics.Paint;
import android.text.Layout;
import android.text.Spannable;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.text.util.Linkify;
import org.telegram.TL.TLObject;
import org.telegram.TL.TLRPC;
import org.telegram.messenger.FileLog;
import org.telegram.messenger.TLObject;
import org.telegram.messenger.TLRPC;
import org.telegram.messenger.Emoji;
import org.telegram.messenger.MessagesController;
import org.telegram.messenger.R;
@ -33,9 +40,33 @@ public class MessageObject {
public PhotoObject previewPhoto;
public String dateKey;
public boolean deleted = false;
public Object TAG;
public float audioProgress;
public int audioProgressSec;
private static TextPaint textPaint;
public int lastLineWidth;
public int textWidth;
public int textHeight;
public int blockHeight = Integer.MAX_VALUE;
public static class TextLayoutBlock {
public StaticLayout textLayout;
public float textXOffset = 0;
public float textYOffset = 0;
public int charactersOffset = 0;
}
private static final int LINES_PER_BLOCK = 10;
public ArrayList<TextLayoutBlock> textLayoutBlocks;
public MessageObject(TLRPC.Message message, AbstractMap<Integer, TLRPC.User> users) {
if (textPaint == null) {
textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
textPaint.setColor(0xff000000);
textPaint.linkColor = 0xff316f9f;
}
messageOwner = message;
if (message instanceof TLRPC.TL_messageService) {
@ -222,7 +253,6 @@ public class MessageObject {
}
messageText = Emoji.replaceEmoji(messageText);
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) {
if (message.from_id == UserConfig.clientUserId) {
@ -268,9 +298,9 @@ public class MessageObject {
}
} else if (message.media != null && message.media instanceof TLRPC.TL_messageMediaAudio) {
if (message.from_id == UserConfig.clientUserId) {
type = 0;
type = 18;
} else {
type = 1;
type = 19;
}
}
} else if (message instanceof TLRPC.TL_messageService) {
@ -295,6 +325,8 @@ public class MessageObject {
int dateYear = rightNow.get(Calendar.YEAR);
int dateMonth = rightNow.get(Calendar.MONTH);
dateKey = String.format("%d_%02d_%02d", dateYear, dateMonth, dateDay);
generateLayout();
}
public String getFileName() {
@ -335,4 +367,122 @@ public class MessageObject {
}
return "";
}
private void generateLayout() {
if (type != 0 && type != 1 && type != 8 && type != 9 || messageOwner.to_id == null || messageText == null || messageText.length() == 0 || !(messageOwner.media instanceof TLRPC.TL_messageMediaEmpty) && !(messageOwner.media instanceof TLRPC.TL_messageMediaUnsupported) && !(messageOwner.media == null)) {
return;
}
textLayoutBlocks = new ArrayList<TextLayoutBlock>();
if (messageText instanceof Spannable) {
if (messageOwner.message != null && messageOwner.message.contains(".")) {
Linkify.addLinks((Spannable)messageText, Linkify.WEB_URLS);
} else if (messageText.length() < 400) {
Linkify.addLinks((Spannable)messageText, Linkify.WEB_URLS | Linkify.EMAIL_ADDRESSES | Linkify.PHONE_NUMBERS);
}
}
textPaint.setTextSize(Utilities.dp(MessagesController.Instance.fontSize));
int maxWidth;
if (messageOwner.to_id.chat_id != 0) {
maxWidth = Math.min(Utilities.displaySize.x, Utilities.displaySize.y) - Utilities.dp(122);
} else {
maxWidth = Math.min(Utilities.displaySize.x, Utilities.displaySize.y) - Utilities.dp(80);
}
StaticLayout textLayout = new StaticLayout(messageText, textPaint, maxWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
textHeight = textLayout.getHeight();
int linesCount = textLayout.getLineCount();
int blocksCount = (int)Math.ceil((float)linesCount / LINES_PER_BLOCK);
int linesOffset = 0;
for (int a = 0; a < blocksCount; a++) {
int currentBlockLinesCount = Math.min(LINES_PER_BLOCK, linesCount - linesOffset);
TextLayoutBlock block = new TextLayoutBlock();
if (blocksCount == 1) {
block.textLayout = textLayout;
block.textYOffset = 0;
block.charactersOffset = 0;
blockHeight = textHeight;
} else {
int startCharacter = textLayout.getLineStart(linesOffset);
int endCharacter = textLayout.getLineEnd(linesOffset + currentBlockLinesCount - 1);
if (endCharacter < startCharacter) {
continue;
}
block.charactersOffset = startCharacter;
CharSequence str = messageText.subSequence(startCharacter, endCharacter);
block.textLayout = new StaticLayout(str, textPaint, maxWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
block.textYOffset = textLayout.getLineTop(linesOffset);
if (a != blocksCount - 1) {
blockHeight = Math.min(blockHeight, block.textLayout.getHeight());
}
}
textLayoutBlocks.add(block);
float lastLeft = block.textXOffset = block.textLayout.getLineLeft(currentBlockLinesCount - 1);
float lastLine = block.textLayout.getLineWidth(currentBlockLinesCount - 1);
int linesMaxWidth;
int lastLineWidthWithLeft;
int linesMaxWidthWithLeft;
boolean hasNonRTL = false;
linesMaxWidth = (int)Math.ceil(lastLine);
if (a == blocksCount - 1) {
lastLineWidth = linesMaxWidth;
}
linesMaxWidthWithLeft = lastLineWidthWithLeft = (int)Math.ceil(lastLine + lastLeft);
if (lastLeft == 0) {
hasNonRTL = true;
}
if (currentBlockLinesCount > 1) {
float textRealMaxWidth = 0, textRealMaxWidthWithLeft = 0, lineWidth, lineLeft;
for (int n = 0; n < currentBlockLinesCount; ++n) {
try {
lineWidth = block.textLayout.getLineWidth(n);
lineLeft = block.textLayout.getLineLeft(n);
block.textXOffset = Math.min(block.textXOffset, lineLeft);
} catch (Exception e) {
FileLog.e("tmessages", e);
return;
}
if (lineLeft == 0) {
hasNonRTL = true;
}
textRealMaxWidth = Math.max(textRealMaxWidth, lineWidth);
textRealMaxWidthWithLeft = Math.max(textRealMaxWidthWithLeft, lineWidth + lineLeft);
linesMaxWidth = Math.max(linesMaxWidth, (int)Math.ceil(lineWidth));
linesMaxWidthWithLeft = Math.max(linesMaxWidthWithLeft, (int)Math.ceil(lineWidth + lineLeft));
}
if (hasNonRTL) {
textRealMaxWidth = textRealMaxWidthWithLeft;
if (a == blocksCount - 1) {
lastLineWidth = lastLineWidthWithLeft;
}
linesMaxWidth = linesMaxWidthWithLeft;
} else if (a == blocksCount - 1) {
lastLineWidth = linesMaxWidth;
}
textWidth = Math.max(textWidth, (int)Math.ceil(textRealMaxWidth));
} else {
textWidth = Math.max(textWidth, Math.min(maxWidth, linesMaxWidth));
}
if (hasNonRTL) {
block.textXOffset = 0;
}
linesOffset += currentBlockLinesCount;
}
}
}

View File

@ -11,7 +11,7 @@ package org.telegram.objects;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import org.telegram.TL.TLRPC;
import org.telegram.messenger.TLRPC;
import org.telegram.messenger.FileLoader;
import java.util.ArrayList;
@ -62,7 +62,7 @@ public class PhotoObject {
for (TLRPC.PhotoSize obj : sizes) {
int diffW = Math.abs(obj.w - width);
int diffH = Math.abs(obj.h - height);
if (closestObject == null || closestWidth > diffW && closestHeight > diffH) {
if (closestObject == null || closestWidth > diffW || closestHeight > diffH) {
closestObject = obj;
closestWidth = diffW;
closestHeight = diffH;

View File

@ -0,0 +1,41 @@
/*
* This is the source code of Telegram for Android v. 1.3.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
*
* Copyright Nikolai Kudashov, 2013-2014.
*/
package org.telegram.ui.Adapters;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
public class BaseFragmentAdapter extends BaseAdapter {
public void onFragmentCreate() {
}
public void onFragmentDestroy() {
}
@Override
public int getCount() {
return 0;
}
@Override
public Object getItem(int i) {
return null;
}
@Override
public long getItemId(int i) {
return 0;
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
return null;
}
}

View File

@ -0,0 +1,231 @@
/*
* This is the source code of Telegram for Android v. 1.3.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
*
* Copyright Nikolai Kudashov, 2013-2014.
*/
package org.telegram.ui.Adapters;
import android.content.Context;
import android.text.Html;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import org.telegram.messenger.TLRPC;
import org.telegram.messenger.ContactsController;
import org.telegram.messenger.MessagesController;
import org.telegram.messenger.R;
import org.telegram.ui.Cells.ChatOrUserCell;
import org.telegram.ui.Views.SectionedBaseAdapter;
import java.util.ArrayList;
import java.util.HashMap;
public class ContactsActivityAdapter extends SectionedBaseAdapter {
private Context mContext;
private boolean onlyUsers;
private boolean usersAsSections;
private HashMap<Integer, TLRPC.User> ignoreUsers;
public ContactsActivityAdapter(Context context, boolean arg1, boolean arg2, HashMap<Integer, TLRPC.User> arg3) {
mContext = context;
onlyUsers = arg1;
usersAsSections = arg2;
ignoreUsers = arg3;
}
@Override
public Object getItem(int section, int position) {
return null;
}
@Override
public long getItemId(int section, int position) {
return 0;
}
@Override
public int getSectionCount() {
int count = 0;
if (usersAsSections) {
count += ContactsController.Instance.sortedUsersSectionsArray.size();
} else {
count++;
}
if (!onlyUsers) {
count += ContactsController.Instance.sortedContactsSectionsArray.size();
}
return count;
}
@Override
public int getCountForSection(int section) {
if (usersAsSections) {
if (section < ContactsController.Instance.sortedUsersSectionsArray.size()) {
ArrayList<TLRPC.TL_contact> arr = ContactsController.Instance.usersSectionsDict.get(ContactsController.Instance.sortedUsersSectionsArray.get(section));
return arr.size();
}
} else {
if (section == 0) {
return ContactsController.Instance.contacts.size() + 1;
}
}
ArrayList<ContactsController.Contact> arr = ContactsController.Instance.contactsSectionsDict.get(ContactsController.Instance.sortedContactsSectionsArray.get(section - 1));
return arr.size();
}
@Override
public View getItemView(int section, int position, View convertView, ViewGroup parent) {
TLRPC.User user = null;
int count = 0;
if (usersAsSections) {
if (section < ContactsController.Instance.sortedUsersSectionsArray.size()) {
ArrayList<TLRPC.TL_contact> arr = ContactsController.Instance.usersSectionsDict.get(ContactsController.Instance.sortedUsersSectionsArray.get(section));
user = MessagesController.Instance.users.get(arr.get(position).user_id);
count = arr.size();
}
} else {
if (section == 0) {
if (position == 0) {
if (convertView == null) {
LayoutInflater li = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = li.inflate(R.layout.contacts_invite_row_layout, parent, false);
}
View divider = convertView.findViewById(R.id.settings_row_divider);
if (ContactsController.Instance.contacts.isEmpty()) {
divider.setVisibility(View.INVISIBLE);
} else {
divider.setVisibility(View.VISIBLE);
}
return convertView;
}
user = MessagesController.Instance.users.get(ContactsController.Instance.contacts.get(position - 1).user_id);
count = ContactsController.Instance.contacts.size();
}
}
if (user != null) {
if (convertView == null) {
convertView = new ChatOrUserCell(mContext);
((ChatOrUserCell)convertView).useBoldFont = true;
((ChatOrUserCell)convertView).usePadding = false;
}
((ChatOrUserCell)convertView).setData(user, null, null, null, null);
if (ignoreUsers != null) {
if (ignoreUsers.containsKey(user.id)) {
((ChatOrUserCell)convertView).drawAlpha = 0.5f;
} else {
((ChatOrUserCell)convertView).drawAlpha = 1.0f;
}
}
((ChatOrUserCell) convertView).useSeparator = position != count - 1;
return convertView;
}
TextView textView;
if (convertView == null) {
LayoutInflater li = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = li.inflate(R.layout.settings_row_button_layout, parent, false);
textView = (TextView)convertView.findViewById(R.id.settings_row_text);
} else {
textView = (TextView)convertView.findViewById(R.id.settings_row_text);
}
View divider = convertView.findViewById(R.id.settings_row_divider);
ArrayList<ContactsController.Contact> arr = ContactsController.Instance.contactsSectionsDict.get(ContactsController.Instance.sortedContactsSectionsArray.get(section - 1));
ContactsController.Contact contact = arr.get(position);
if (divider != null) {
if (position == arr.size() - 1) {
divider.setVisibility(View.INVISIBLE);
} else {
divider.setVisibility(View.VISIBLE);
}
}
if (contact.first_name != null && contact.last_name != null) {
textView.setText(Html.fromHtml(contact.first_name + " <b>" + contact.last_name + "</b>"));
} else if (contact.first_name != null && contact.last_name == null) {
textView.setText(Html.fromHtml("<b>" + contact.first_name + "</b>"));
} else {
textView.setText(Html.fromHtml("<b>" + contact.last_name + "</b>"));
}
return convertView;
}
@Override
public int getItemViewType(int section, int position) {
if (usersAsSections) {
if (section < ContactsController.Instance.sortedUsersSectionsArray.size()) {
return 0;
}
} else if (section == 0) {
if (position == 0) {
return 2;
}
return 0;
}
return 1;
}
@Override
public int getItemViewTypeCount() {
return 3;
}
@Override
public int getSectionHeaderViewType(int section) {
if (usersAsSections) {
if (section < ContactsController.Instance.sortedUsersSectionsArray.size()) {
return 1;
}
} else if (section == 0) {
return 0;
}
return 1;
}
@Override
public int getSectionHeaderViewTypeCount() {
return 2;
}
@Override
public View getSectionHeaderView(int section, View convertView, ViewGroup parent) {
if (usersAsSections) {
if (section < ContactsController.Instance.sortedUsersSectionsArray.size()) {
if (convertView == null) {
LayoutInflater li = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = li.inflate(R.layout.settings_section_layout, parent, false);
convertView.setBackgroundColor(0xffffffff);
}
TextView textView = (TextView)convertView.findViewById(R.id.settings_section_text);
textView.setText(ContactsController.Instance.sortedUsersSectionsArray.get(section));
return convertView;
}
} else {
if (section == 0) {
if (convertView == null) {
LayoutInflater li = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = li.inflate(R.layout.empty_layout, parent, false);
}
return convertView;
}
}
if (convertView == null) {
LayoutInflater li = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = li.inflate(R.layout.settings_section_layout, parent, false);
convertView.setBackgroundColor(0xffffffff);
}
TextView textView = (TextView)convertView.findViewById(R.id.settings_section_text);
textView.setText(ContactsController.Instance.sortedContactsSectionsArray.get(section - 1));
return convertView;
}
}

View File

@ -0,0 +1,187 @@
/*
* This is the source code of Telegram for Android v. 1.3.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
*
* Copyright Nikolai Kudashov, 2013-2014.
*/
package org.telegram.ui.Adapters;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import org.telegram.messenger.TLRPC;
import org.telegram.messenger.ContactsController;
import org.telegram.messenger.FileLog;
import org.telegram.messenger.MessagesController;
import org.telegram.messenger.UserConfig;
import org.telegram.messenger.Utilities;
import org.telegram.ui.Cells.ChatOrUserCell;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Timer;
import java.util.TimerTask;
public class ContactsActivitySearchAdapter extends BaseFragmentAdapter {
private Context mContext;
private HashMap<Integer, TLRPC.User> ignoreUsers;
private ArrayList<TLRPC.User> searchResult;
private ArrayList<CharSequence> searchResultNames;
private Timer searchDialogsTimer;
public ContactsActivitySearchAdapter(Context context, HashMap<Integer, TLRPC.User> arg1) {
mContext = context;
ignoreUsers = arg1;
}
public void searchDialogs(final String query) {
if (query == null) {
searchResult = null;
searchResultNames = null;
notifyDataSetChanged();
} else {
try {
if (searchDialogsTimer != null) {
searchDialogsTimer.cancel();
}
} catch (Exception e) {
FileLog.e("tmessages", e);
}
searchDialogsTimer = new Timer();
searchDialogsTimer.schedule(new TimerTask() {
@Override
public void run() {
try {
searchDialogsTimer.cancel();
searchDialogsTimer = null;
} catch (Exception e) {
FileLog.e("tmessages", e);
}
processSearch(query);
}
}, 100, 300);
}
}
private void processSearch(final String query) {
Utilities.globalQueue.postRunnable(new Runnable() {
@Override
public void run() {
String q = query.trim().toLowerCase();
if (q.length() == 0) {
updateSearchResults(new ArrayList<TLRPC.User>(), new ArrayList<CharSequence>());
return;
}
long time = System.currentTimeMillis();
ArrayList<TLRPC.User> resultArray = new ArrayList<TLRPC.User>();
ArrayList<CharSequence> resultArrayNames = new ArrayList<CharSequence>();
for (TLRPC.TL_contact contact : ContactsController.Instance.contacts) {
TLRPC.User user = MessagesController.Instance.users.get(contact.user_id);
if (user.first_name != null && user.first_name.toLowerCase().startsWith(q) || user.last_name != null && user.last_name.toLowerCase().startsWith(q)) {
if (user.id == UserConfig.clientUserId) {
continue;
}
resultArrayNames.add(Utilities.generateSearchName(user.first_name, user.last_name, q));
resultArray.add(user);
}
}
updateSearchResults(resultArray, resultArrayNames);
}
});
}
private void updateSearchResults(final ArrayList<TLRPC.User> users, final ArrayList<CharSequence> names) {
Utilities.RunOnUIThread(new Runnable() {
@Override
public void run() {
searchResult = users;
searchResultNames = names;
notifyDataSetChanged();
}
});
}
@Override
public boolean areAllItemsEnabled() {
return true;
}
@Override
public boolean isEnabled(int i) {
return true;
}
@Override
public int getCount() {
if (searchResult == null) {
return 0;
}
return searchResult.size();
}
@Override
public TLRPC.User getItem(int i) {
if (searchResult != null) {
if (i >= 0 && i < searchResult.size()) {
return searchResult.get(i);
}
}
return null;
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public boolean hasStableIds() {
return false;
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
if (view == null) {
view = new ChatOrUserCell(mContext);
((ChatOrUserCell)view).usePadding = false;
}
((ChatOrUserCell) view).useSeparator = i != searchResult.size() - 1;
Object obj = searchResult.get(i);
TLRPC.User user = MessagesController.Instance.users.get(((TLRPC.User)obj).id);
if (user != null) {
((ChatOrUserCell)view).setData(user, null, null, searchResultNames.get(i), null);
if (ignoreUsers != null) {
if (ignoreUsers.containsKey(user.id)) {
((ChatOrUserCell)view).drawAlpha = 0.5f;
} else {
((ChatOrUserCell)view).drawAlpha = 1.0f;
}
}
}
return view;
}
@Override
public int getItemViewType(int i) {
return 0;
}
@Override
public int getViewTypeCount() {
return 1;
}
@Override
public boolean isEmpty() {
return searchResult == null || searchResult.size() == 0;
}
}

View File

@ -51,6 +51,9 @@ public class ApplicationActivity extends ActionBarActivity implements Notificati
private String photoPath = null;
private String videoPath = null;
private String sendingText = null;
private String documentPath = null;
private String[] imagesPathArray = null;
private String[] documentsPathArray = null;
private int currentConnectionState;
private View statusView;
private View backStatusButton;
@ -117,6 +120,9 @@ public class ApplicationActivity extends ActionBarActivity implements Notificati
photoPath = (String)NotificationCenter.Instance.getFromMemCache(533);
videoPath = (String)NotificationCenter.Instance.getFromMemCache(534);
sendingText = (String)NotificationCenter.Instance.getFromMemCache(535);
documentPath = (String)NotificationCenter.Instance.getFromMemCache(536);
imagesPathArray = (String[])NotificationCenter.Instance.getFromMemCache(537);
documentsPathArray = (String[])NotificationCenter.Instance.getFromMemCache(538);
if (push_user_id != 0) {
if (push_user_id == UserConfig.clientUserId) {
@ -153,7 +159,7 @@ public class ApplicationActivity extends ActionBarActivity implements Notificati
getSupportFragmentManager().beginTransaction().replace(R.id.container, fragment, "chat" + Math.random()).commitAllowingStateLoss();
}
}
if (videoPath != null || photoPath != null || sendingText != null) {
if (videoPath != null || photoPath != null || sendingText != null || documentPath != null || documentsPathArray != null || imagesPathArray != null) {
MessagesActivity fragment = new MessagesActivity();
fragment.selectAlertString = R.string.ForwardMessagesTo;
fragment.animationType = 1;
@ -217,7 +223,10 @@ public class ApplicationActivity extends ActionBarActivity implements Notificati
photoPath = (String)NotificationCenter.Instance.getFromMemCache(533);
videoPath = (String)NotificationCenter.Instance.getFromMemCache(534);
sendingText = (String)NotificationCenter.Instance.getFromMemCache(535);
if (videoPath != null || photoPath != null || sendingText != null) {
documentPath = (String)NotificationCenter.Instance.getFromMemCache(536);
imagesPathArray = (String[])NotificationCenter.Instance.getFromMemCache(537);
documentsPathArray = (String[])NotificationCenter.Instance.getFromMemCache(538);
if (videoPath != null || photoPath != null || sendingText != null || documentPath != null || imagesPathArray != null || documentsPathArray != null) {
MessagesActivity fragment = new MessagesActivity();
fragment.selectAlertString = R.string.ForwardMessagesTo;
fragment.animationType = 1;
@ -310,10 +319,23 @@ public class ApplicationActivity extends ActionBarActivity implements Notificati
fragment.processSendingVideo(videoPath);
} else if (sendingText != null) {
fragment.processSendingText(sendingText);
} else if (documentPath != null) {
fragment.processSendingDocument(documentPath);
} else if (imagesPathArray != null) {
for (String path : imagesPathArray) {
fragment.processSendingPhoto(path);
}
} else if (documentsPathArray != null) {
for (String path : documentsPathArray) {
fragment.processSendingDocument(path);
}
}
photoPath = null;
videoPath = null;
sendingText = null;
documentPath = null;
imagesPathArray = null;
documentsPathArray = null;
}
}
@ -387,6 +409,7 @@ public class ApplicationActivity extends ActionBarActivity implements Notificati
@Override
public void onConfigurationChanged(android.content.res.Configuration newConfig) {
super.onConfigurationChanged(newConfig);
Utilities.checkDisplaySize();
fixLayout();
}

View File

@ -11,7 +11,6 @@ package org.telegram.ui;
import android.app.Activity;
import android.app.Application;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
@ -26,7 +25,6 @@ import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.gcm.GoogleCloudMessaging;
import org.telegram.PhoneFormat.PhoneFormat;
import org.telegram.messenger.BackgroundService;
import org.telegram.messenger.ConnectionsManager;
import org.telegram.messenger.FileLog;
import org.telegram.messenger.MessagesController;
@ -45,7 +43,6 @@ public class ApplicationLoader extends Application {
private GoogleCloudMessaging gcm;
private AtomicInteger msgId = new AtomicInteger();
private String regid;
private String SENDER_ID = "760348033672";
public static final String EXTRA_MESSAGE = "message";
public static final String PROPERTY_REG_ID = "registration_id";
private static final String PROPERTY_APP_VERSION = "appVersion";
@ -133,8 +130,6 @@ public class ApplicationLoader extends Application {
lastPauseTime = System.currentTimeMillis();
FileLog.e("tmessages", "start application with time " + lastPauseTime);
startService(new Intent(this, BackgroundService.class));
}
@Override
@ -149,6 +144,7 @@ public class ApplicationLoader extends Application {
}
currentLocale = newLocale;
}
Utilities.checkDisplaySize();
}
public static void resetLastPauseTime() {
@ -210,7 +206,7 @@ public class ApplicationLoader extends Application {
while (count < 1000) {
try {
count++;
regid = gcm.register(SENDER_ID);
regid = gcm.register(ConnectionsManager.GCM_SENDER_ID);
sendRegistrationIdToBackend(true);
storeRegistrationId(applicationContext, regid);
return true;

View File

@ -10,7 +10,6 @@ package org.telegram.ui.Cells;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;
public class BaseCell extends View {
@ -18,14 +17,6 @@ public class BaseCell extends View {
super(context);
}
public BaseCell(Context context, AttributeSet attrs) {
super(context, attrs);
}
public BaseCell(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
protected void setDrawableBounds(Drawable drawable, int x, int y) {
setDrawableBounds(drawable, x, y, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
}

View File

@ -0,0 +1,396 @@
/*
* This is the source code of Telegram for Android v. 1.3.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
*
* Copyright Nikolai Kudashov, 2013-2014.
*/
package org.telegram.ui.Cells;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.text.Layout;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.view.MotionEvent;
import android.view.SoundEffectConstants;
import android.view.View;
import org.telegram.messenger.FileLoader;
import org.telegram.messenger.MediaController;
import org.telegram.messenger.TLRPC;
import org.telegram.messenger.MessagesController;
import org.telegram.messenger.R;
import org.telegram.messenger.Utilities;
import org.telegram.objects.MessageObject;
import org.telegram.ui.Views.ImageReceiver;
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 {
private static Drawable[][] statesDrawable = new Drawable[8][2];
private static TextPaint timePaint;
private ImageReceiver avatarImage;
private SeekBar seekBar;
private ProgressView progressView;
private int seekBarX;
private int seekBarY;
private int buttonState = 0;
private int buttonX;
private int buttonY;
private int buttonPressed = 0;
private int avatarPressed = 0;
private StaticLayout timeLayout;
private int timeX;
private String lastTimeString = null;
private int TAG;
public TLRPC.User audioUser;
private TLRPC.FileLocation currentPhoto;
private String currentNameString;
public ChatAudioCell(Context context, boolean isChat) {
super(context, isChat);
TAG = MediaController.Instance.generateObserverTag();
avatarImage = new ImageReceiver();
avatarImage.parentView = new WeakReference<View>(this);
seekBar = new SeekBar(context);
seekBar.delegate = this;
progressView = new ProgressView();
if (timePaint == null) {
statesDrawable[0][0] = getResources().getDrawable(R.drawable.play1);
statesDrawable[0][1] = getResources().getDrawable(R.drawable.play1_pressed);
statesDrawable[1][0] = getResources().getDrawable(R.drawable.pause1);
statesDrawable[1][1] = getResources().getDrawable(R.drawable.pause1_pressed);
statesDrawable[2][0] = getResources().getDrawable(R.drawable.audioload1);
statesDrawable[2][1] = getResources().getDrawable(R.drawable.audioload1_pressed);
statesDrawable[3][0] = getResources().getDrawable(R.drawable.audiocancel1);
statesDrawable[3][1] = getResources().getDrawable(R.drawable.audiocancel1_pressed);
statesDrawable[4][0] = getResources().getDrawable(R.drawable.play2);
statesDrawable[4][1] = getResources().getDrawable(R.drawable.play2_pressed);
statesDrawable[5][0] = getResources().getDrawable(R.drawable.pause2);
statesDrawable[5][1] = getResources().getDrawable(R.drawable.pause2_pressed);
statesDrawable[6][0] = getResources().getDrawable(R.drawable.audioload2);
statesDrawable[6][1] = getResources().getDrawable(R.drawable.audioload2_pressed);
statesDrawable[7][0] = getResources().getDrawable(R.drawable.audiocancel2);
statesDrawable[7][1] = getResources().getDrawable(R.drawable.audiocancel2_pressed);
timePaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG);
timePaint.setTextSize(Utilities.dp(12));
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
boolean result = seekBar.onTouch(event.getAction(), event.getX() - seekBarX, event.getY() - seekBarY);
if (result) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
getParent().requestDisallowInterceptTouchEvent(true);
}
invalidate();
} else {
int side = Utilities.dp(36);
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if (x >= buttonX && x <= buttonX + side && y >= buttonY && y <= buttonY + side) {
buttonPressed = 1;
invalidate();
result = true;
} else if (x >= avatarImage.imageX && x <= avatarImage.imageX + avatarImage.imageW && y >= avatarImage.imageY && y <= avatarImage.imageY + avatarImage.imageH) {
avatarPressed = 1;
result = true;
}
} else if (buttonPressed == 1) {
if (event.getAction() == MotionEvent.ACTION_UP) {
buttonPressed = 0;
playSoundEffect(SoundEffectConstants.CLICK);
didPressedButton();
invalidate();
} else if (event.getAction() == MotionEvent.ACTION_CANCEL) {
buttonPressed = 0;
invalidate();
} else if (event.getAction() == MotionEvent.ACTION_MOVE) {
if (!(x >= buttonX && x <= buttonX + side && y >= buttonY && y <= buttonY + side)) {
buttonPressed = 0;
invalidate();
}
}
} else if (avatarPressed == 1) {
if (event.getAction() == MotionEvent.ACTION_UP) {
avatarPressed = 0;
playSoundEffect(SoundEffectConstants.CLICK);
if (delegate != null) {
delegate.didPressedUserAvatar(this, audioUser);
}
} else if (event.getAction() == MotionEvent.ACTION_CANCEL) {
avatarPressed = 0;
} else if (event.getAction() == MotionEvent.ACTION_MOVE) {
if (!(x >= avatarImage.imageX && x <= avatarImage.imageX + avatarImage.imageW && y >= avatarImage.imageY && y <= avatarImage.imageY + avatarImage.imageH)) {
avatarPressed = 0;
}
}
}
if (!result) {
result = super.onTouchEvent(event);
}
}
return result;
}
private void didPressedButton() {
if (buttonState == 0) {
boolean result = MediaController.Instance.playAudio(currentMessageObject);
if (result) {
buttonState = 1;
invalidate();
}
} else if (buttonState == 1) {
boolean result = MediaController.Instance.pauseAudio(currentMessageObject);
if (result) {
buttonState = 0;
invalidate();
}
} else if (buttonState == 2) {
FileLoader.Instance.loadFile(null, null, null, currentMessageObject.messageOwner.media.audio);
buttonState = 3;
invalidate();
} else if (buttonState == 3) {
FileLoader.Instance.cancelLoadFile(null, null, null, currentMessageObject.messageOwner.media.audio);
buttonState = 2;
invalidate();
}
}
public void updateProgress() {
if (currentMessageObject == null) {
return;
}
if (!seekBar.isDragging()) {
seekBar.setProgress(currentMessageObject.audioProgress);
}
int duration = 0;
if (!MediaController.Instance.isPlayingAudio(currentMessageObject)) {
duration = currentMessageObject.messageOwner.media.audio.duration;
} else {
duration = currentMessageObject.audioProgressSec;
}
String timeString = String.format("%02d:%02d", duration / 60, duration % 60);
if (lastTimeString == null || lastTimeString != null && !lastTimeString.equals(timeString)) {
int timeWidth = (int)Math.ceil(timePaint.measureText(timeString));
timeLayout = new StaticLayout(timeString, timePaint, timeWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
}
invalidate();
}
public void updateButtonState() {
String fileName = currentMessageObject.getFileName();
File cacheFile = new File(Utilities.getCacheDir(), fileName);
if (cacheFile.exists()) {
MediaController.Instance.removeLoadingFileObserver(this);
boolean playing = MediaController.Instance.isPlayingAudio(currentMessageObject);
if (!playing || playing && MediaController.Instance.isAudioPaused()) {
buttonState = 0;
} else {
buttonState = 1;
}
progressView.setProgress(0);
} else {
MediaController.Instance.addLoadingFileObserver(currentMessageObject.getFileName(), this);
if (!FileLoader.Instance.isLoadingFile(fileName)) {
buttonState = 2;
progressView.setProgress(0);
} else {
buttonState = 3;
Float progress = FileLoader.Instance.fileProgresses.get(fileName);
if (progress != null) {
progressView.setProgress(progress);
} else {
progressView.setProgress(0);
}
}
}
updateProgress();
}
@Override
public void onFailedDownload(String fileName) {
updateButtonState();
}
@Override
public void onSuccessDownload(String fileName) {
updateButtonState();
}
@Override
public void onProgressDownload(String fileName, float progress) {
progressView.setProgress(progress);
invalidate();
}
@Override
public int getObserverTag() {
return TAG;
}
@Override
public void onSeekBarDrag(float progress) {
if (currentMessageObject == null) {
return;
}
currentMessageObject.audioProgress = progress;
MediaController.Instance.seekToProgress(currentMessageObject, progress);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = MeasureSpec.getSize(widthMeasureSpec);
setMeasuredDimension(width, Utilities.dp(68));
if (chat) {
backgroundWidth = Math.min(width - Utilities.dp(102), Utilities.dp(300));
} else {
backgroundWidth = Math.min(width - Utilities.dp(50), Utilities.dp(300));
}
}
@SuppressLint("DrawAllocation")
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
if (currentMessageObject.messageOwner.out) {
avatarImage.imageX = layoutWidth - backgroundWidth + Utilities.dp(9);
seekBarX = layoutWidth - backgroundWidth + Utilities.dp(94);
buttonX = layoutWidth - backgroundWidth + Utilities.dp(63);
timeX = layoutWidth - backgroundWidth + Utilities.dp(67);
} else {
if (chat) {
avatarImage.imageX = Utilities.dp(69);
seekBarX = Utilities.dp(155);
buttonX = Utilities.dp(124);
timeX = Utilities.dp(128);
} else {
avatarImage.imageX = Utilities.dp(16);
seekBarX = Utilities.dp(103);
buttonX = Utilities.dp(72);
timeX = Utilities.dp(76);
}
}
avatarImage.imageY = Utilities.dp(9);
avatarImage.imageW = Utilities.dp(50);
avatarImage.imageH = Utilities.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);
updateProgress();
}
@Override
protected boolean isUserDataChanged() {
TLRPC.User newUser = MessagesController.Instance.users.get(currentMessageObject.messageOwner.media.audio.user_id);
TLRPC.FileLocation newPhoto = null;
if (avatarImage != null && newUser != null && newUser.photo != null) {
newPhoto = newUser.photo.photo_small;
}
return currentPhoto == null && newPhoto != null || currentPhoto != null && newPhoto == null || currentPhoto != null && newPhoto != null && (currentPhoto.local_id != newPhoto.local_id || currentPhoto.volume_id != newPhoto.volume_id) || super.isUserDataChanged();
}
@Override
public void setMessageObject(MessageObject messageObject) {
if (currentMessageObject != messageObject || isUserDataChanged()) {
int uid = messageObject.messageOwner.media.audio.user_id;
audioUser = MessagesController.Instance.users.get(uid);
if (audioUser != null) {
if (audioUser.photo != null) {
currentPhoto = audioUser.photo.photo_small;
}
avatarImage.setImage(currentPhoto, "50_50", getResources().getDrawable(Utilities.getUserAvatarForId(uid)));
} else {
avatarImage.setImage((TLRPC.FileLocation)null, "50_50", getResources().getDrawable(Utilities.getUserAvatarForId(uid)));
}
if (messageObject.messageOwner.out) {
seekBar.type = 0;
progressView.type = 0;
} else {
seekBar.type = 1;
progressView.type = 1;
}
super.setMessageObject(messageObject);
}
updateButtonState();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (currentMessageObject == null) {
return;
}
avatarImage.draw(canvas, avatarImage.imageX, avatarImage.imageY, Utilities.dp(50), Utilities.dp(50));
canvas.save();
if (buttonState == 0 || buttonState == 1) {
canvas.translate(seekBarX, seekBarY);
seekBar.draw(canvas);
} else {
canvas.translate(seekBarX + Utilities.dp(12), seekBarY);
progressView.draw(canvas);
}
canvas.restore();
int state = buttonState;
if (!currentMessageObject.messageOwner.out) {
state += 4;
timePaint.setColor(0xffa1aab3);
} else {
timePaint.setColor(0xff70b15c);
}
Drawable buttonDrawable = statesDrawable[state][buttonPressed];
int side = Utilities.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));
timeLayout.draw(canvas);
canvas.restore();
}
@Override
protected void finalize() throws Throwable {
MediaController.Instance.removeLoadingFileObserver(this);
super.finalize();
}
}

View File

@ -0,0 +1,461 @@
/*
* This is the source code of Telegram for Android v. 1.3.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
*
* Copyright Nikolai Kudashov, 2013-2014.
*/
package org.telegram.ui.Cells;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.text.Html;
import android.text.Layout;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.text.TextUtils;
import android.view.MotionEvent;
import android.view.SoundEffectConstants;
import android.view.View;
import org.telegram.messenger.TLRPC;
import org.telegram.messenger.MessagesController;
import org.telegram.messenger.R;
import org.telegram.messenger.Utilities;
import org.telegram.objects.MessageObject;
import org.telegram.ui.ApplicationLoader;
import org.telegram.ui.Views.ImageReceiver;
import java.lang.ref.WeakReference;
public class ChatBaseCell extends BaseCell {
public static interface ChatBaseCellDelegate {
public abstract void didPressedUserAvatar(ChatBaseCell cell, TLRPC.User user);
}
protected boolean chat;
protected boolean isPressed = false;
protected boolean forwardName = false;
private boolean isCheckPressed = true;
private boolean wasLayout = false;
protected MessageObject currentMessageObject;
private static Drawable backgroundDrawableIn;
private static Drawable backgroundDrawableInSelected;
private static Drawable backgroundDrawableOut;
private static Drawable backgroundDrawableOutSelected;
private static Drawable checkDrawable;
private static Drawable halfCheckDrawable;
private static Drawable clockDrawable;
private static Drawable errorDrawable;
private static TextPaint timePaintIn;
private static TextPaint timePaintOut;
private static TextPaint namePaint;
private static TextPaint forwardNamePaint;
protected int backgroundWidth = 100;
protected int layoutWidth;
protected int layoutHeight;
private ImageReceiver avatarImage;
private boolean avatarPressed = false;
private boolean forwardNamePressed = false;
private StaticLayout nameLayout;
protected int nameWidth;
protected boolean drawName = false;
private StaticLayout forwardedNameLayout;
protected int forwardedNameWidth;
protected boolean drawForwardedName = false;
private int forwardNameX;
private int forwardNameY;
private StaticLayout timeLayout;
protected int timeWidth;
protected int timeX;
private TextPaint currentTimePaint;
private String currentTimeString;
private TLRPC.User currentUser;
private TLRPC.FileLocation currentPhoto;
private String currentNameString;
private TLRPC.User currentForwardUser;
private String currentForwardNameString;
public ChatBaseCellDelegate delegate;
protected int namesOffset = 0;
public ChatBaseCell(Context context, boolean isChat) {
super(context);
init();
chat = isChat;
if (chat) {
avatarImage = new ImageReceiver();
avatarImage.parentView = new WeakReference<View>(this);
}
}
private void init() {
if (backgroundDrawableIn == null) {
backgroundDrawableIn = getResources().getDrawable(R.drawable.msg_in);
backgroundDrawableInSelected = getResources().getDrawable(R.drawable.msg_in_selected);
backgroundDrawableOut = getResources().getDrawable(R.drawable.msg_out);
backgroundDrawableOutSelected = getResources().getDrawable(R.drawable.msg_out_selected);
checkDrawable = getResources().getDrawable(R.drawable.msg_check);
halfCheckDrawable = getResources().getDrawable(R.drawable.msg_halfcheck);
clockDrawable = getResources().getDrawable(R.drawable.msg_clock);
errorDrawable = getResources().getDrawable(R.drawable.msg_warning);
timePaintIn = new TextPaint(TextPaint.ANTI_ALIAS_FLAG);
timePaintIn.setTextSize(Utilities.dp(12));
timePaintIn.setColor(0xffa1aab3);
timePaintOut = new TextPaint(TextPaint.ANTI_ALIAS_FLAG);
timePaintOut.setTextSize(Utilities.dp(12));
timePaintOut.setColor(0xff70b15c);
namePaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG);
namePaint.setTextSize(Utilities.dp(15));
forwardNamePaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG);
forwardNamePaint.setTextSize(Utilities.dp(14));
}
}
@Override
public void setPressed(boolean pressed) {
super.setPressed(pressed);
invalidate();
}
public void setCheckPressed(boolean value, boolean pressed) {
isCheckPressed = value;
isPressed = pressed;
invalidate();
}
protected boolean isUserDataChanged() {
if (currentMessageObject == null || currentUser == null) {
return false;
}
TLRPC.User newUser = MessagesController.Instance.users.get(currentMessageObject.messageOwner.from_id);
TLRPC.FileLocation newPhoto = null;
if (avatarImage != null && newUser != null && newUser.photo != null) {
newPhoto = newUser.photo.photo_small;
}
if (currentPhoto == null && newPhoto != null || currentPhoto != null && newPhoto == null || currentPhoto != null && newPhoto != null && (currentPhoto.local_id != newPhoto.local_id || currentPhoto.volume_id != newPhoto.volume_id)) {
return true;
}
String newNameString = null;
if (drawName && chat && newUser != null && !currentMessageObject.messageOwner.out) {
newNameString = Utilities.formatName(newUser.first_name, newUser.last_name);
}
if (currentNameString == null && newNameString != null || currentNameString != null && newNameString == null || currentNameString != null && newNameString != null && !currentNameString.equals(newNameString)) {
return true;
}
newUser = MessagesController.Instance.users.get(currentMessageObject.messageOwner.fwd_from_id);
newNameString = null;
if (drawForwardedName && currentMessageObject.messageOwner instanceof TLRPC.TL_messageForwarded) {
newNameString = Utilities.formatName(newUser.first_name, newUser.last_name);
}
return currentForwardNameString == null && newNameString != null || currentForwardNameString != null && newNameString == null || currentForwardNameString != null && newNameString != null && !currentForwardNameString.equals(newNameString);
}
public void setMessageObject(MessageObject messageObject) {
currentMessageObject = messageObject;
isPressed = false;
isCheckPressed = true;
wasLayout = false;
if (currentMessageObject.messageOwner.id < 0 && currentMessageObject.messageOwner.send_state != MessagesController.MESSAGE_SEND_STATE_SEND_ERROR && currentMessageObject.messageOwner.send_state != MessagesController.MESSAGE_SEND_STATE_SENT) {
if (MessagesController.Instance.sendingMessages.get(currentMessageObject.messageOwner.id) == null) {
currentMessageObject.messageOwner.send_state = MessagesController.MESSAGE_SEND_STATE_SEND_ERROR;
}
}
currentUser = MessagesController.Instance.users.get(messageObject.messageOwner.from_id);
if (avatarImage != null) {
if (currentUser != null) {
if (currentUser.photo != null) {
currentPhoto = currentUser.photo.photo_small;
}
avatarImage.setImage(currentPhoto, "50_50", getResources().getDrawable(Utilities.getUserAvatarForId(currentUser.id)));
} else {
avatarImage.setImage((TLRPC.FileLocation)null, "50_50", null);
}
}
if (currentMessageObject.messageOwner.out) {
currentTimePaint = timePaintOut;
} else {
currentTimePaint = timePaintIn;
}
currentTimeString = Utilities.formatterDay.format((long) (currentMessageObject.messageOwner.date) * 1000);
timeWidth = (int)Math.ceil(currentTimePaint.measureText(currentTimeString));
namesOffset = 0;
if (drawName && chat && currentUser != null && !currentMessageObject.messageOwner.out) {
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);
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);
} else {
nameWidth = 0;
}
} else {
currentNameString = null;
nameLayout = null;
nameWidth = 0;
}
if (drawForwardedName && messageObject.messageOwner instanceof TLRPC.TL_messageForwarded) {
currentForwardUser = MessagesController.Instance.users.get(messageObject.messageOwner.fwd_from_id);
if (currentForwardUser != null) {
currentForwardNameString = Utilities.formatName(currentForwardUser.first_name, currentForwardUser.last_name);
forwardedNameWidth = getMaxNameWidth();
CharSequence str = TextUtils.ellipsize(currentForwardNameString.replace("\n", " "), forwardNamePaint, forwardedNameWidth - Utilities.dp(40), TextUtils.TruncateAt.END);
str = Html.fromHtml(String.format("%s<br>%s <b>%s</b>", ApplicationLoader.applicationContext.getString(R.string.ForwardedMessage), ApplicationLoader.applicationContext.getString(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);
} else {
forwardedNameWidth = 0;
}
} else {
currentForwardNameString = null;
forwardedNameLayout = null;
forwardedNameWidth = 0;
}
} else {
currentForwardNameString = null;
forwardedNameLayout = null;
forwardedNameWidth = 0;
}
requestLayout();
}
public final MessageObject getMessageObject() {
return currentMessageObject;
}
protected int getMaxNameWidth() {
return backgroundWidth - Utilities.dp(8);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
boolean result = false;
float x = event.getX();
float y = event.getY();
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if (avatarImage != null && x >= avatarImage.imageX && x <= avatarImage.imageX + avatarImage.imageW && y >= avatarImage.imageY && y <= avatarImage.imageY + avatarImage.imageH) {
avatarPressed = true;
result = true;
} else if (drawForwardedName && forwardedNameLayout != null) {
if (x >= forwardNameX && x <= forwardNameX + forwardedNameWidth && y >= forwardNameY && y <= forwardNameY + Utilities.dp(32)) {
forwardNamePressed = true;
result = true;
}
}
} else if (avatarPressed) {
if (event.getAction() == MotionEvent.ACTION_UP) {
avatarPressed = false;
playSoundEffect(SoundEffectConstants.CLICK);
if (delegate != null) {
delegate.didPressedUserAvatar(this, currentUser);
}
} else if (event.getAction() == MotionEvent.ACTION_CANCEL) {
avatarPressed = false;
} else if (event.getAction() == MotionEvent.ACTION_MOVE) {
if (avatarImage != null && !(x >= avatarImage.imageX && x <= avatarImage.imageX + avatarImage.imageW && y >= avatarImage.imageY && y <= avatarImage.imageY + avatarImage.imageH)) {
avatarPressed = false;
}
}
} else if (forwardNamePressed) {
if (event.getAction() == MotionEvent.ACTION_UP) {
forwardNamePressed = false;
playSoundEffect(SoundEffectConstants.CLICK);
if (delegate != null) {
delegate.didPressedUserAvatar(this, currentForwardUser);
}
} 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))) {
forwardNamePressed = false;
}
}
}
return result;
}
@SuppressLint("DrawAllocation")
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
if (currentMessageObject == null) {
super.onLayout(changed, left, top, right, bottom);
return;
}
if (changed || !wasLayout) {
layoutWidth = getMeasuredWidth();
layoutHeight = getMeasuredHeight();
timeLayout = new StaticLayout(currentTimeString, currentTimePaint, timeWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false);
if (!currentMessageObject.messageOwner.out) {
timeX = backgroundWidth - Utilities.dp(9) - timeWidth + (chat ? Utilities.dp(52) : 0);
} else {
timeX = layoutWidth - timeWidth - Utilities.dpf(38.5f);
}
if (avatarImage != null) {
avatarImage.imageX = Utilities.dp(6);
avatarImage.imageY = layoutHeight - Utilities.dp(45);
avatarImage.imageW = Utilities.dp(42);
avatarImage.imageH = Utilities.dp(42);
}
wasLayout = true;
}
}
@Override
protected void onDraw(Canvas canvas) {
if (currentMessageObject == null) {
return;
}
if (!wasLayout) {
requestFocus();
return;
}
if (avatarImage != null) {
avatarImage.draw(canvas, Utilities.dp(6), layoutHeight - Utilities.dp(45), Utilities.dp(42), Utilities.dp(42));
}
Drawable currentBackgroundDrawable = null;
if (currentMessageObject.messageOwner.out) {
if (isPressed() && isCheckPressed || !isCheckPressed && isPressed) {
currentBackgroundDrawable = backgroundDrawableOutSelected;
} else {
currentBackgroundDrawable = backgroundDrawableOut;
}
setDrawableBounds(currentBackgroundDrawable, layoutWidth - backgroundWidth, Utilities.dp(1), backgroundWidth, layoutHeight - Utilities.dp(2));
} else {
if (isPressed() && isCheckPressed || !isCheckPressed && isPressed) {
currentBackgroundDrawable = backgroundDrawableInSelected;
} else {
currentBackgroundDrawable = backgroundDrawableIn;
}
if (chat) {
setDrawableBounds(currentBackgroundDrawable, Utilities.dp(52), Utilities.dp(1), backgroundWidth, layoutHeight - Utilities.dp(2));
} else {
setDrawableBounds(currentBackgroundDrawable, 0, Utilities.dp(1), backgroundWidth, layoutHeight - Utilities.dp(2));
}
}
currentBackgroundDrawable.draw(canvas);
if (drawName && nameLayout != null) {
canvas.save();
canvas.translate(currentBackgroundDrawable.getBounds().left + Utilities.dp(19), Utilities.dp(10));
namePaint.setColor(Utilities.getColorForId(currentUser.id));
nameLayout.draw(canvas);
canvas.restore();
}
if (drawForwardedName && forwardedNameLayout != null) {
canvas.save();
if (currentMessageObject.messageOwner.out) {
forwardNamePaint.setColor(0xff4a923c);
forwardNameX = currentBackgroundDrawable.getBounds().left + Utilities.dp(10);
forwardNameY = Utilities.dp(10 + (drawName ? 18 : 0));
} else {
forwardNamePaint.setColor(0xff006fc8);
forwardNameX = currentBackgroundDrawable.getBounds().left + Utilities.dp(19);
forwardNameY = Utilities.dp(10 + (drawName ? 18 : 0));
}
canvas.translate(forwardNameX, forwardNameY);
forwardedNameLayout.draw(canvas);
canvas.restore();
}
canvas.save();
canvas.translate(timeX, layoutHeight - Utilities.dpf(6.5f) - timeLayout.getHeight());
timeLayout.draw(canvas);
canvas.restore();
if (currentMessageObject.messageOwner.out) {
boolean drawCheck1 = false;
boolean drawCheck2 = false;
boolean drawClock = false;
boolean drawError = false;
if (currentMessageObject.messageOwner.send_state == MessagesController.MESSAGE_SEND_STATE_SENDING) {
drawCheck1 = false;
drawCheck2 = false;
drawClock = true;
drawError = false;
} else if (currentMessageObject.messageOwner.send_state == MessagesController.MESSAGE_SEND_STATE_SEND_ERROR) {
drawCheck1 = false;
drawCheck2 = false;
drawClock = false;
drawError = true;
} else if (currentMessageObject.messageOwner.send_state == MessagesController.MESSAGE_SEND_STATE_SENT) {
if (!currentMessageObject.messageOwner.unread) {
drawCheck1 = true;
drawCheck2 = true;
} else {
drawCheck1 = false;
drawCheck2 = true;
}
drawClock = false;
drawError = false;
}
if (drawClock) {
setDrawableBounds(clockDrawable, layoutWidth - Utilities.dpf(18.5f) - clockDrawable.getIntrinsicWidth(), layoutHeight - Utilities.dpf(8.5f) - clockDrawable.getIntrinsicHeight());
clockDrawable.draw(canvas);
}
if (drawCheck2) {
if (drawCheck1) {
setDrawableBounds(checkDrawable, layoutWidth - Utilities.dpf(22.5f) - checkDrawable.getIntrinsicWidth(), layoutHeight - Utilities.dpf(8.5f) - checkDrawable.getIntrinsicHeight());
} else {
setDrawableBounds(checkDrawable, layoutWidth - Utilities.dpf(18.5f) - checkDrawable.getIntrinsicWidth(), layoutHeight - Utilities.dpf(8.5f) - checkDrawable.getIntrinsicHeight());
}
checkDrawable.draw(canvas);
}
if (drawCheck1) {
setDrawableBounds(halfCheckDrawable, layoutWidth - Utilities.dp(18) - halfCheckDrawable.getIntrinsicWidth(), layoutHeight - Utilities.dpf(8.5f) - halfCheckDrawable.getIntrinsicHeight());
halfCheckDrawable.draw(canvas);
}
if (drawError) {
setDrawableBounds(errorDrawable, layoutWidth - Utilities.dp(18) - errorDrawable.getIntrinsicWidth(), layoutHeight - Utilities.dpf(6.5f) - errorDrawable.getIntrinsicHeight());
errorDrawable.draw(canvas);
}
}
}
}

View File

@ -9,18 +9,199 @@
package org.telegram.ui.Cells;
import android.content.Context;
import android.util.AttributeSet;
import android.graphics.Canvas;
import android.text.Spannable;
import android.text.style.ClickableSpan;
import android.util.Log;
import android.view.MotionEvent;
public class ChatMessageCell extends BaseCell {
public ChatMessageCell(Context context) {
super(context);
import org.telegram.messenger.Utilities;
import org.telegram.objects.MessageObject;
public class ChatMessageCell extends ChatBaseCell {
private int textX, textY;
private int totalHeight = 0;
private ClickableSpan pressedLink;
private int visibleY = 0;
private int visibleHeight = 0;
private int lastVisibleBlockNum = 0;
private int firstVisibleBlockNum = 0;
private int totalVisibleBlocksCount = 0;
public ChatMessageCell(Context context, boolean isChat) {
super(context, isChat);
drawForwardedName = true;
}
public ChatMessageCell(Context context, AttributeSet attrs) {
super(context, attrs);
@Override
public boolean onTouchEvent(MotionEvent event) {
if (currentMessageObject != null && currentMessageObject.messageText instanceof Spannable && !isPressed) {
if (event.getAction() == MotionEvent.ACTION_DOWN || pressedLink != null && event.getAction() == MotionEvent.ACTION_UP) {
int x = (int)event.getX();
int y = (int)event.getY();
if (x >= textX && y >= textY && x <= textX + currentMessageObject.textWidth && y <= textY + currentMessageObject.textHeight) {
y -= textY;
int blockNum = Math.max(0, y / currentMessageObject.blockHeight);
if (blockNum < currentMessageObject.textLayoutBlocks.size()) {
MessageObject.TextLayoutBlock block = currentMessageObject.textLayoutBlocks.get(blockNum);
x -= textX - (int)Math.ceil(block.textXOffset);
y -= block.textYOffset;
final int line = block.textLayout.getLineForVertical(y);
final int off = block.textLayout.getOffsetForHorizontal(line, x) + block.charactersOffset;
final float left = block.textLayout.getLineLeft(line);
if (left <= x && left + block.textLayout.getLineWidth(line) >= x) {
Spannable buffer = (Spannable)currentMessageObject.messageText;
ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class);
if (link.length != 0) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
pressedLink = link[0];
return true;
} else {
if (link[0] == pressedLink) {
pressedLink.onClick(this);
return true;
}
}
} else {
pressedLink = null;
}
} else {
pressedLink = null;
}
} else {
pressedLink = null;
}
} else {
pressedLink = null;
}
}
} else {
pressedLink = null;
}
return super.onTouchEvent(event);
}
public ChatMessageCell(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
public void setVisiblePart(int position, int height) {
visibleY = position;
visibleHeight = height;
if (visibleY < 0) {
Log.e("tmessages", "vis = " + visibleY);
}
int newFirst = -1, newLast = -1, newCount = 0;
for (int a = Math.max(0, (visibleY - textY) / currentMessageObject.blockHeight); a < currentMessageObject.textLayoutBlocks.size(); a++) {
MessageObject.TextLayoutBlock block = currentMessageObject.textLayoutBlocks.get(a);
float y = textY + block.textYOffset;
if (intersect(y, y + currentMessageObject.blockHeight, visibleY, visibleY + visibleHeight)) {
if (newFirst == -1) {
newFirst = a;
}
newLast = a;
newCount++;
} else if (y > visibleY) {
break;
}
}
if (lastVisibleBlockNum != newLast || firstVisibleBlockNum != newFirst || totalVisibleBlocksCount != newCount) {
lastVisibleBlockNum = newLast;
firstVisibleBlockNum = newFirst;
totalVisibleBlocksCount = newCount;
invalidate();
}
}
private boolean intersect(float left1, float right1, float left2, float right2) {
if (left1 <= left2) {
return right1 >= left2;
}
return left1 <= right2;
}
@Override
public void setMessageObject(MessageObject messageObject) {
if (currentMessageObject != messageObject || isUserDataChanged()) {
pressedLink = null;
int maxWidth;
if (chat) {
maxWidth = Utilities.displaySize.x - Utilities.dp(122);
drawName = true;
} else {
maxWidth = Utilities.displaySize.x - Utilities.dp(80);
}
backgroundWidth = maxWidth;
super.setMessageObject(messageObject);
backgroundWidth = messageObject.textWidth;
totalHeight = messageObject.textHeight + Utilities.dpf(19.5f) + namesOffset;
int maxChildWidth = Math.max(backgroundWidth, nameWidth);
maxChildWidth = Math.max(maxChildWidth, forwardedNameWidth);
int timeMore = timeWidth + Utilities.dp(6);
if (messageObject.messageOwner.out) {
timeMore += Utilities.dpf(20.5f);
}
if (maxWidth - messageObject.lastLineWidth < timeMore) {
totalHeight += Utilities.dp(14);
backgroundWidth = Math.max(maxChildWidth, messageObject.lastLineWidth) + Utilities.dp(29);
} else {
int diff = maxChildWidth - messageObject.lastLineWidth;
if (diff >= 0 && diff <= timeMore) {
backgroundWidth = maxChildWidth + timeMore - diff + Utilities.dp(29);
} else {
backgroundWidth = Math.max(maxChildWidth, messageObject.lastLineWidth + timeMore) + Utilities.dp(29);
}
}
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), totalHeight);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
if (changed) {
if (currentMessageObject.messageOwner.out) {
textX = layoutWidth - backgroundWidth + Utilities.dp(10);
textY = Utilities.dp(10) + namesOffset;
} else {
textX = Utilities.dp(19) + (chat ? Utilities.dp(52) : 0);
textY = Utilities.dp(10) + namesOffset;
}
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (currentMessageObject == null || currentMessageObject.textLayoutBlocks == null || currentMessageObject.textLayoutBlocks.isEmpty()) {
return;
}
for (int a = Math.max(0, (visibleY - textY) / currentMessageObject.blockHeight); a < currentMessageObject.textLayoutBlocks.size(); a++) {
MessageObject.TextLayoutBlock block = currentMessageObject.textLayoutBlocks.get(a);
float y = textY + block.textYOffset;
if (intersect(y, y + currentMessageObject.blockHeight, visibleY, visibleY + visibleHeight)) {
canvas.save();
canvas.translate(textX - (int)Math.ceil(block.textXOffset), textY + block.textYOffset);
block.textLayout.draw(canvas);
canvas.restore();
} else {
break;
}
}
}
}

View File

@ -17,11 +17,10 @@ import android.text.Layout;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
import org.telegram.PhoneFormat.PhoneFormat;
import org.telegram.TL.TLRPC;
import org.telegram.messenger.TLRPC;
import org.telegram.messenger.ConnectionsManager;
import org.telegram.messenger.ContactsController;
import org.telegram.messenger.MessagesController;
@ -65,16 +64,6 @@ public class ChatOrUserCell extends BaseCell {
init();
}
public ChatOrUserCell(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public ChatOrUserCell(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
if (namePaint == null) {
namePaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG);
@ -174,9 +163,6 @@ public class ChatOrUserCell extends BaseCell {
int newStatus = 0;
if (user.status != null) {
newStatus = user.status.expires;
if (lastStatus == 0) {
lastStatus = user.status.was_online;
}
}
if (newStatus != lastStatus) {
continueUpdate = true;
@ -202,9 +188,6 @@ public class ChatOrUserCell extends BaseCell {
if (user != null) {
if (user.status != null) {
lastStatus = user.status.expires;
if (lastStatus == 0) {
lastStatus = user.status.was_online;
}
} else {
lastStatus = 0;
}
@ -326,7 +309,7 @@ public class ChatOrUserCell extends BaseCell {
if (chat != null) {
nameString2 = chat.title;
} else if (user != null) {
if (user.id != 333000 && ContactsController.Instance.contactsDict.get(user.id) == null) {
if (user.id / 1000 != 333 && ContactsController.Instance.contactsDict.get(user.id) == null) {
if (ContactsController.Instance.contactsDict.size() == 0 && ContactsController.Instance.loadingContacts) {
nameString2 = Utilities.formatName(user.first_name, user.last_name);
} else {
@ -382,18 +365,14 @@ public class ChatOrUserCell extends BaseCell {
onlineString = getResources().getString(R.string.Offline);
} else {
int currentTime = ConnectionsManager.Instance.getCurrentTime();
if (user.id == UserConfig.clientUserId || user.status.expires > currentTime || user.status.was_online > currentTime) {
if (user.id == UserConfig.clientUserId || user.status.expires > currentTime) {
currentOnlinePaint = onlinePaint;
onlineString = getResources().getString(R.string.Online);
} else {
if (user.status.was_online <= 10000 && user.status.expires <= 10000) {
if (user.status.expires <= 10000) {
onlineString = getResources().getString(R.string.Invisible);
} else {
int value = user.status.was_online;
if (value == 0) {
value = user.status.expires;
}
onlineString = Utilities.formatDateOnline(value);
onlineString = Utilities.formatDateOnline(user.status.expires);
}
}
}

View File

@ -16,11 +16,10 @@ import android.text.Layout;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
import org.telegram.PhoneFormat.PhoneFormat;
import org.telegram.TL.TLRPC;
import org.telegram.messenger.TLRPC;
import org.telegram.messenger.ContactsController;
import org.telegram.messenger.Emoji;
import org.telegram.messenger.MessagesController;
@ -143,16 +142,6 @@ public class DialogCell extends BaseCell {
init();
}
public DialogCell(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public DialogCell(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public void setDialog(TLRPC.TL_dialog dialog) {
currentDialog = dialog;
update(0);
@ -525,7 +514,7 @@ public class DialogCell extends BaseCell {
if (chat != null) {
nameString = chat.title;
} else if (user != null) {
if (user.id != 333000 && ContactsController.Instance.contactsDict.get(user.id) == null) {
if (user.id / 1000 != 333 && ContactsController.Instance.contactsDict.get(user.id) == null) {
if (ContactsController.Instance.contactsDict.size() == 0 && (!ContactsController.Instance.contactsLoaded || ContactsController.Instance.loadingContacts)) {
nameString = Utilities.formatName(user.first_name, user.last_name);
} else {

File diff suppressed because it is too large Load Diff

View File

@ -36,7 +36,7 @@ import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import org.telegram.TL.TLRPC;
import org.telegram.messenger.TLRPC;
import org.telegram.messenger.ConnectionsManager;
import org.telegram.messenger.FileLog;
import org.telegram.messenger.MessagesController;
@ -279,7 +279,7 @@ public class ChatProfileActivity extends BaseFragment implements NotificationCen
public void didReceivedNotification(int id, Object... args) {
if (id == MessagesController.updateInterfaces) {
int mask = (Integer)args[0];
if ((mask & MessagesController.UPDATE_MASK_CHAT_AVATAR) != 0 || (mask & MessagesController.UPDATE_MASK_CHAT_NAME) != 0 || (mask & MessagesController.UPDATE_MASK_CHAT_MEMBERS) != 0) {
if ((mask & MessagesController.UPDATE_MASK_CHAT_AVATAR) != 0 || (mask & MessagesController.UPDATE_MASK_CHAT_NAME) != 0 || (mask & MessagesController.UPDATE_MASK_CHAT_MEMBERS) != 0 || (mask & MessagesController.UPDATE_MASK_STATUS) != 0) {
updateOnlineCount();
}
if ((mask & MessagesController.UPDATE_MASK_AVATAR) != 0 || (mask & MessagesController.UPDATE_MASK_NAME) != 0 || (mask & MessagesController.UPDATE_MASK_STATUS) != 0) {
@ -382,7 +382,7 @@ public class ChatProfileActivity extends BaseFragment implements NotificationCen
int i = 0;
for (TLRPC.TL_chatParticipant participant : info.participants) {
TLRPC.User user = MessagesController.Instance.users.get(participant.user_id);
if (user != null && user.status != null && (user.status.expires > currentTime || user.status.was_online > currentTime || user.id == UserConfig.clientUserId) && (user.status.expires > 10000 || user.status.was_online > 10000)) {
if (user != null && user.status != null && (user.status.expires > currentTime || user.id == UserConfig.clientUserId) && user.status.expires > 10000) {
onlineCount++;
}
sortedUsers.add(i);
@ -401,9 +401,6 @@ public class ChatProfileActivity extends BaseFragment implements NotificationCen
status1 = ConnectionsManager.Instance.getCurrentTime() + 50000;
} else {
status1 = user1.status.expires;
if (status1 == 0) {
status1 = user1.status.was_online;
}
}
}
if (user2 != null && user2.status != null) {
@ -411,9 +408,6 @@ public class ChatProfileActivity extends BaseFragment implements NotificationCen
status2 = ConnectionsManager.Instance.getCurrentTime() + 50000;
} else {
status2 = user2.status.expires;
if (status2 == 0) {
status2 = user2.status.was_online;
}
}
}
return status1.compareTo(status2);

View File

@ -22,7 +22,7 @@ import android.view.inputmethod.EditorInfo;
import android.widget.EditText;
import android.widget.TextView;
import org.telegram.TL.TLRPC;
import org.telegram.messenger.TLRPC;
import org.telegram.messenger.MessagesController;
import org.telegram.messenger.R;
import org.telegram.messenger.Utilities;

View File

@ -24,7 +24,7 @@ import android.widget.EditText;
import android.widget.TextView;
import org.telegram.PhoneFormat.PhoneFormat;
import org.telegram.TL.TLRPC;
import org.telegram.messenger.TLRPC;
import org.telegram.messenger.ConnectionsManager;
import org.telegram.messenger.ContactsController;
import org.telegram.messenger.MessagesController;
@ -131,17 +131,13 @@ public class ContactAddActivity extends BaseFragment implements NotificationCent
onlineText.setText(getStringEntry(R.string.Offline));
} else {
int currentTime = ConnectionsManager.Instance.getCurrentTime();
if (user.status.expires > currentTime || user.status.was_online > currentTime) {
if (user.status.expires > currentTime) {
onlineText.setText(getStringEntry(R.string.Online));
} else {
if (user.status.was_online <= 10000 && user.status.expires <= 10000) {
if (user.status.expires <= 10000) {
onlineText.setText(getStringEntry(R.string.Invisible));
} else {
int value = user.status.was_online;
if (value == 0) {
value = user.status.expires;
}
onlineText.setText(Utilities.formatDateOnline(value));
onlineText.setText(Utilities.formatDateOnline(user.status.expires));
}
}
}

View File

@ -10,7 +10,6 @@ package org.telegram.ui;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
@ -20,7 +19,6 @@ import android.support.v4.internal.view.SupportMenuItem;
import android.support.v4.view.MenuItemCompat;
import android.support.v7.app.ActionBar;
import android.support.v7.widget.SearchView;
import android.text.Html;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
@ -28,12 +26,11 @@ import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import org.telegram.TL.TLObject;
import org.telegram.TL.TLRPC;
import org.telegram.messenger.TLObject;
import org.telegram.messenger.TLRPC;
import org.telegram.messenger.ConnectionsManager;
import org.telegram.messenger.ContactsController;
import org.telegram.messenger.FileLog;
@ -43,6 +40,8 @@ import org.telegram.messenger.R;
import org.telegram.messenger.RPCRequest;
import org.telegram.messenger.UserConfig;
import org.telegram.messenger.Utilities;
import org.telegram.ui.Adapters.ContactsActivityAdapter;
import org.telegram.ui.Adapters.ContactsActivitySearchAdapter;
import org.telegram.ui.Cells.ChatOrUserCell;
import org.telegram.ui.Views.BaseFragment;
import org.telegram.ui.Views.OnSwipeTouchListener;
@ -54,13 +53,11 @@ import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Locale;
import java.util.Timer;
import java.util.TimerTask;
public class ContactsActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate {
private SectionedBaseAdapter listViewAdapter;
private PinnedHeaderListView listView;
private BaseAdapter searchListViewAdapter;
private ContactsActivitySearchAdapter searchListViewAdapter;
private boolean searchWas;
private boolean searching;
private boolean onlyUsers;
@ -75,11 +72,8 @@ public class ContactsActivity extends BaseFragment implements NotificationCenter
private HashMap<Integer, TLRPC.User> ignoreUsers;
private SupportMenuItem searchItem;
private Timer searchDialogsTimer;
private String inviteText;
private boolean updatingInviteText = false;
public ArrayList<TLRPC.User> searchResult;
public ArrayList<CharSequence> searchResultNames;
public ContactsActivityDelegate delegate;
public static interface ContactsActivityDelegate {
@ -144,22 +138,26 @@ public class ContactsActivity extends BaseFragment implements NotificationCenter
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
if (fragmentView == null) {
searching = false;
searchWas = false;
fragmentView = inflater.inflate(R.layout.contacts_layout, container, false);
epmtyTextView = (TextView)fragmentView.findViewById(R.id.searchEmptyView);
searchListViewAdapter = new SearchAdapter(parentActivity);
searchListViewAdapter = new ContactsActivitySearchAdapter(parentActivity, ignoreUsers);
listView = (PinnedHeaderListView)fragmentView.findViewById(R.id.listView);
listView.setEmptyView(epmtyTextView);
listView.setVerticalScrollBarEnabled(false);
listView.setAdapter(listViewAdapter = new ListAdapter(parentActivity));
listViewAdapter = new ContactsActivityAdapter(parentActivity, onlyUsers, usersAsSections, ignoreUsers);
listView.setAdapter(listViewAdapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
if (searching && searchWas) {
TLRPC.User user = searchResult.get(i);
if (user.id == UserConfig.clientUserId) {
TLRPC.User user = searchListViewAdapter.getItem(i);
if (user == null || user.id == UserConfig.clientUserId) {
return;
}
if (returnAsResult) {
@ -379,75 +377,6 @@ public class ContactsActivity extends BaseFragment implements NotificationCenter
((ApplicationActivity)parentActivity).updateActionBar();
}
public void searchDialogs(final String query) {
if (query == null) {
searchResult = null;
searchResultNames = null;
} else {
try {
if (searchDialogsTimer != null) {
searchDialogsTimer.cancel();
}
} catch (Exception e) {
FileLog.e("tmessages", e);
}
searchDialogsTimer = new Timer();
searchDialogsTimer.schedule(new TimerTask() {
@Override
public void run() {
try {
searchDialogsTimer.cancel();
searchDialogsTimer = null;
} catch (Exception e) {
FileLog.e("tmessages", e);
}
processSearch(query);
}
}, 100, 300);
}
}
private void processSearch(final String query) {
Utilities.globalQueue.postRunnable(new Runnable() {
@Override
public void run() {
String q = query.trim().toLowerCase();
if (q.length() == 0) {
updateSearchResults(new ArrayList<TLRPC.User>(), new ArrayList<CharSequence>());
return;
}
long time = System.currentTimeMillis();
ArrayList<TLRPC.User> resultArray = new ArrayList<TLRPC.User>();
ArrayList<CharSequence> resultArrayNames = new ArrayList<CharSequence>();
for (TLRPC.TL_contact contact : ContactsController.Instance.contacts) {
TLRPC.User user = MessagesController.Instance.users.get(contact.user_id);
if (user.first_name != null && user.first_name.toLowerCase().startsWith(q) || user.last_name != null && user.last_name.toLowerCase().startsWith(q)) {
if (user.id == UserConfig.clientUserId) {
continue;
}
resultArrayNames.add(Utilities.generateSearchName(user.first_name, user.last_name, q));
resultArray.add(user);
}
}
updateSearchResults(resultArray, resultArrayNames);
}
});
}
private void updateSearchResults(final ArrayList<TLRPC.User> users, final ArrayList<CharSequence> names) {
Utilities.RunOnUIThread(new Runnable() {
@Override
public void run() {
searchResult = users;
searchResultNames = names;
searchListViewAdapter.notifyDataSetChanged();
}
});
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int itemId = item.getItemId();
@ -497,7 +426,10 @@ public class ContactsActivity extends BaseFragment implements NotificationCenter
@Override
public boolean onQueryTextChange(String s) {
searchDialogs(s);
if (searchListViewAdapter == null) {
return true;
}
searchListViewAdapter.searchDialogs(s);
if (s.length() != 0) {
searchWas = true;
if (listView != null) {
@ -531,7 +463,7 @@ public class ContactsActivity extends BaseFragment implements NotificationCenter
@Override
public boolean onMenuItemActionCollapse(MenuItem menuItem) {
searchView.setQuery("", false);
searchDialogs(null);
searchListViewAdapter.searchDialogs(null);
searching = false;
searchWas = false;
ViewGroup group = (ViewGroup) listView.getParent();
@ -578,331 +510,46 @@ public class ContactsActivity extends BaseFragment implements NotificationCenter
}
private void updateInviteText() {
if (updatingInviteText) {
return;
}
updatingInviteText = true;
TLRPC.TL_help_getInviteText req = new TLRPC.TL_help_getInviteText();
req.lang_code = Locale.getDefault().getCountry();
if (req.lang_code == null || req.lang_code.length() == 0) {
req.lang_code = "en";
}
ConnectionsManager.Instance.performRpc(req, new RPCRequest.RPCRequestDelegate() {
@Override
public void run(TLObject response, TLRPC.TL_error error) {
if (error != null) {
return;
}
final TLRPC.TL_help_inviteText res = (TLRPC.TL_help_inviteText)response;
if (res.message.length() == 0) {
return;
}
Utilities.RunOnUIThread(new Runnable() {
@Override
public void run() {
updatingInviteText = false;
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE);
SharedPreferences.Editor editor = preferences.edit();
editor.putString("invitetext", res.message);
editor.putInt("invitetexttime", (int) (System.currentTimeMillis() / 1000));
editor.commit();
}
});
if (!updatingInviteText) {
updatingInviteText = true;
TLRPC.TL_help_getInviteText req = new TLRPC.TL_help_getInviteText();
req.lang_code = Locale.getDefault().getCountry();
if (req.lang_code == null || req.lang_code.length() == 0) {
req.lang_code = "en";
}
}, null, true, RPCRequest.RPCRequestClassGeneric | RPCRequest.RPCRequestClassFailOnServerErrors);
ConnectionsManager.Instance.performRpc(req, new RPCRequest.RPCRequestDelegate() {
@Override
public void run(TLObject response, TLRPC.TL_error error) {
if (error == null) {
final TLRPC.TL_help_inviteText res = (TLRPC.TL_help_inviteText)response;
if (res.message.length() != 0) {
Utilities.RunOnUIThread(new Runnable() {
@Override
public void run() {
updatingInviteText = false;
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE);
SharedPreferences.Editor editor = preferences.edit();
editor.putString("invitetext", res.message);
editor.putInt("invitetexttime", (int) (System.currentTimeMillis() / 1000));
editor.commit();
}
});
}
}
}
}, null, true, RPCRequest.RPCRequestClassGeneric | RPCRequest.RPCRequestClassFailOnServerErrors);
}
}
private void updateVisibleRows(int mask) {
if (listView == null) {
return;
}
int count = listView.getChildCount();
for (int a = 0; a < count; a++) {
View child = listView.getChildAt(a);
if (child instanceof ChatOrUserCell) {
((ChatOrUserCell) child).update(mask);
}
}
}
private class SearchAdapter extends BaseAdapter {
private Context mContext;
public SearchAdapter(Context context) {
mContext = context;
}
@Override
public boolean areAllItemsEnabled() {
return true;
}
@Override
public boolean isEnabled(int i) {
return true;
}
@Override
public int getCount() {
if (searchResult == null) {
return 0;
}
return searchResult.size();
}
@Override
public Object getItem(int i) {
return null;
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public boolean hasStableIds() {
return false;
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
if (view == null) {
view = new ChatOrUserCell(mContext);
((ChatOrUserCell)view).usePadding = false;
}
((ChatOrUserCell) view).useSeparator = i != searchResult.size() - 1;
Object obj = searchResult.get(i);
TLRPC.User user = MessagesController.Instance.users.get(((TLRPC.User)obj).id);
if (user != null) {
((ChatOrUserCell)view).setData(user, null, null, searchResultNames.get(i), null);
if (ignoreUsers != null) {
if (ignoreUsers.containsKey(user.id)) {
((ChatOrUserCell)view).drawAlpha = 0.5f;
} else {
((ChatOrUserCell)view).drawAlpha = 1.0f;
}
if (listView != null) {
int count = listView.getChildCount();
for (int a = 0; a < count; a++) {
View child = listView.getChildAt(a);
if (child instanceof ChatOrUserCell) {
((ChatOrUserCell) child).update(mask);
}
}
return view;
}
@Override
public int getItemViewType(int i) {
return 0;
}
@Override
public int getViewTypeCount() {
return 1;
}
@Override
public boolean isEmpty() {
return searchResult == null || searchResult.size() == 0;
}
}
private class ListAdapter extends SectionedBaseAdapter {
private Context mContext;
public ListAdapter(Context context) {
mContext = context;
}
@Override
public Object getItem(int section, int position) {
return null;
}
@Override
public long getItemId(int section, int position) {
return 0;
}
@Override
public int getSectionCount() {
int count = 0;
if (usersAsSections) {
count += ContactsController.Instance.sortedUsersSectionsArray.size();
} else {
count++;
}
if (!onlyUsers) {
count += ContactsController.Instance.sortedContactsSectionsArray.size();
}
return count;
}
@Override
public int getCountForSection(int section) {
if (usersAsSections) {
if (section < ContactsController.Instance.sortedUsersSectionsArray.size()) {
ArrayList<TLRPC.TL_contact> arr = ContactsController.Instance.usersSectionsDict.get(ContactsController.Instance.sortedUsersSectionsArray.get(section));
return arr.size();
}
} else {
if (section == 0) {
return ContactsController.Instance.contacts.size() + 1;
}
}
ArrayList<ContactsController.Contact> arr = ContactsController.Instance.contactsSectionsDict.get(ContactsController.Instance.sortedContactsSectionsArray.get(section - 1));
return arr.size();
}
@Override
public View getItemView(int section, int position, View convertView, ViewGroup parent) {
TLRPC.User user = null;
int count = 0;
if (usersAsSections) {
if (section < ContactsController.Instance.sortedUsersSectionsArray.size()) {
ArrayList<TLRPC.TL_contact> arr = ContactsController.Instance.usersSectionsDict.get(ContactsController.Instance.sortedUsersSectionsArray.get(section));
user = MessagesController.Instance.users.get(arr.get(position).user_id);
count = arr.size();
}
} else {
if (section == 0) {
if (position == 0) {
if (convertView == null) {
LayoutInflater li = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = li.inflate(R.layout.contacts_invite_row_layout, parent, false);
}
View divider = convertView.findViewById(R.id.settings_row_divider);
if (ContactsController.Instance.contacts.isEmpty()) {
divider.setVisibility(View.INVISIBLE);
} else {
divider.setVisibility(View.VISIBLE);
}
return convertView;
}
user = MessagesController.Instance.users.get(ContactsController.Instance.contacts.get(position - 1).user_id);
count = ContactsController.Instance.contacts.size();
}
}
if (user != null) {
if (convertView == null) {
convertView = new ChatOrUserCell(mContext);
((ChatOrUserCell)convertView).useBoldFont = true;
((ChatOrUserCell)convertView).usePadding = false;
}
((ChatOrUserCell)convertView).setData(user, null, null, null, null);
if (ignoreUsers != null) {
if (ignoreUsers.containsKey(user.id)) {
((ChatOrUserCell)convertView).drawAlpha = 0.5f;
} else {
((ChatOrUserCell)convertView).drawAlpha = 1.0f;
}
}
((ChatOrUserCell) convertView).useSeparator = position != count - 1;
return convertView;
}
TextView textView;
if (convertView == null) {
LayoutInflater li = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = li.inflate(R.layout.settings_row_button_layout, parent, false);
textView = (TextView)convertView.findViewById(R.id.settings_row_text);
} else {
textView = (TextView)convertView.findViewById(R.id.settings_row_text);
}
View divider = convertView.findViewById(R.id.settings_row_divider);
ArrayList<ContactsController.Contact> arr = ContactsController.Instance.contactsSectionsDict.get(ContactsController.Instance.sortedContactsSectionsArray.get(section - 1));
ContactsController.Contact contact = arr.get(position);
if (divider != null) {
if (position == arr.size() - 1) {
divider.setVisibility(View.INVISIBLE);
} else {
divider.setVisibility(View.VISIBLE);
}
}
if (contact.first_name != null && contact.last_name != null) {
textView.setText(Html.fromHtml(contact.first_name + " <b>" + contact.last_name + "</b>"));
} else if (contact.first_name != null && contact.last_name == null) {
textView.setText(Html.fromHtml("<b>" + contact.first_name + "</b>"));
} else {
textView.setText(Html.fromHtml("<b>" + contact.last_name + "</b>"));
}
return convertView;
}
@Override
public int getItemViewType(int section, int position) {
if (usersAsSections) {
if (section < ContactsController.Instance.sortedUsersSectionsArray.size()) {
return 0;
}
} else if (section == 0) {
if (position == 0) {
return 2;
}
return 0;
}
return 1;
}
@Override
public int getItemViewTypeCount() {
return 3;
}
@Override
public int getSectionHeaderViewType(int section) {
if (usersAsSections) {
if (section < ContactsController.Instance.sortedUsersSectionsArray.size()) {
return 1;
}
} else if (section == 0) {
return 0;
}
return 1;
}
@Override
public int getSectionHeaderViewTypeCount() {
return 2;
}
@Override
public View getSectionHeaderView(int section, View convertView, ViewGroup parent) {
if (usersAsSections) {
if (section < ContactsController.Instance.sortedUsersSectionsArray.size()) {
if (convertView == null) {
LayoutInflater li = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = li.inflate(R.layout.settings_section_layout, parent, false);
convertView.setBackgroundColor(0xffffffff);
}
TextView textView = (TextView)convertView.findViewById(R.id.settings_section_text);
textView.setText(ContactsController.Instance.sortedUsersSectionsArray.get(section));
return convertView;
}
} else {
if (section == 0) {
if (convertView == null) {
LayoutInflater li = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = li.inflate(R.layout.empty_layout, parent, false);
}
return convertView;
}
}
if (convertView == null) {
LayoutInflater li = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = li.inflate(R.layout.settings_section_layout, parent, false);
convertView.setBackgroundColor(0xffffffff);
}
TextView textView = (TextView)convertView.findViewById(R.id.settings_section_text);
textView.setText(ContactsController.Instance.sortedContactsSectionsArray.get(section - 1));
return convertView;
}
}
}

View File

@ -69,6 +69,9 @@ public class CountrySelectActivity extends ActionBarActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
searching = false;
searchWas = false;
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(getResources().getAssets().open("countries.txt")));
String line;

View File

@ -79,10 +79,14 @@ public class DocumentSelectActivity extends BaseFragment {
public void onReceive(Context arg0, Intent intent) {
Runnable r = new Runnable() {
public void run() {
if (currentDir == null){
listRoots();
} else {
listFiles(currentDir);
try {
if (currentDir == null){
listRoots();
} else {
listFiles(currentDir);
}
} catch (Exception e) {
FileLog.e("tmessages", e);
}
}
};

View File

@ -35,7 +35,7 @@ import org.telegram.objects.PhotoObject;
import org.telegram.ui.Views.AbstractGalleryActivity;
import org.telegram.ui.Views.GalleryViewPager;
import org.telegram.ui.Views.PZSImageView;
import org.telegram.TL.TLRPC;
import org.telegram.messenger.TLRPC;
import org.telegram.objects.MessageObject;
import org.telegram.messenger.FileLoader;
import org.telegram.messenger.MessagesController;
@ -479,7 +479,7 @@ public class GalleryImageViewer extends AbstractGalleryActivity implements Notif
}
private TLRPC.FileLocation getCurrentFile() {
if (mViewPager == null) {
if (mViewPager == null || localPagerAdapter == null) {
return null;
}
int item = mViewPager.getCurrentItem();
@ -497,7 +497,16 @@ public class GalleryImageViewer extends AbstractGalleryActivity implements Notif
}
}
} else if (message.messageOwner.media instanceof TLRPC.TL_messageMediaPhoto) {
TLRPC.PhotoSize sizeFull = PhotoObject.getClosestPhotoSizeWithSize(message.messageOwner.media.photo.sizes, 800, 800);
int width = (int)(Math.min(displaySize.x, displaySize.y) * 0.7f);
int height = width + Utilities.dp(100);
if (width > 800) {
width = 800;
}
if (height > 800) {
height = 800;
}
TLRPC.PhotoSize sizeFull = PhotoObject.getClosestPhotoSizeWithSize(message.messageOwner.media.photo.sizes, width, height);
if (sizeFull != null) {
return sizeFull.location;
}
@ -538,7 +547,16 @@ public class GalleryImageViewer extends AbstractGalleryActivity implements Notif
} else {
ArrayList<TLRPC.PhotoSize> sizes = obj.messageOwner.action.photo.sizes;
if (sizes.size() > 0) {
TLRPC.PhotoSize sizeFull = PhotoObject.getClosestPhotoSizeWithSize(sizes, 800, 800);
int width = (int)(Math.min(displaySize.x, displaySize.y) * 0.7f);
int height = width + Utilities.dp(100);
if (width > 800) {
width = 800;
}
if (height > 800) {
height = 800;
}
TLRPC.PhotoSize sizeFull = PhotoObject.getClosestPhotoSizeWithSize(sizes, width, height);
if (sizeFull != null) {
currentFileName = sizeFull.location.volume_id + "_" + sizeFull.location.local_id + ".jpg";
}
@ -634,10 +652,14 @@ public class GalleryImageViewer extends AbstractGalleryActivity implements Notif
obs.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
mViewPager.beginFakeDrag();
if (mViewPager.isFakeDragging()) {
mViewPager.fakeDragBy(1);
mViewPager.endFakeDrag();
try {
mViewPager.beginFakeDrag();
if (mViewPager.isFakeDragging()) {
mViewPager.fakeDragBy(1);
mViewPager.endFakeDrag();
}
} catch (Exception e) {
FileLog.e("tmessages", e);
}
mViewPager.getViewTreeObserver().removeOnPreDrawListener(this);
return false;
@ -660,7 +682,9 @@ public class GalleryImageViewer extends AbstractGalleryActivity implements Notif
switch (itemId) {
case android.R.id.home:
cancelRunning = true;
mViewPager.setAdapter(null);
if (mViewPager != null) {
mViewPager.setAdapter(null);
}
localPagerAdapter = null;
finish();
System.gc();

View File

@ -35,7 +35,7 @@ import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;
import org.telegram.TL.TLRPC;
import org.telegram.messenger.TLRPC;
import org.telegram.messenger.ConnectionsManager;
import org.telegram.messenger.ContactsController;
import org.telegram.messenger.Emoji;
@ -106,6 +106,10 @@ public class GroupCreateActivity extends BaseFragment implements NotificationCen
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
if (fragmentView == null) {
searching = false;
searchWas = false;
fragmentView = inflater.inflate(R.layout.group_create_layout, container, false);
epmtyTextView = (TextView)fragmentView.findViewById(R.id.searchEmptyView);
@ -546,18 +550,14 @@ public class GroupCreateActivity extends BaseFragment implements NotificationCen
holder.messageTextView.setTextColor(0xff808080);
} else {
int currentTime = ConnectionsManager.Instance.getCurrentTime();
if (user.status.expires > currentTime || user.status.was_online > currentTime) {
if (user.status.expires > currentTime) {
holder.messageTextView.setTextColor(0xff357aa8);
holder.messageTextView.setText(getStringEntry(R.string.Online));
} else {
if (user.status.was_online <= 10000 && user.status.expires <= 10000) {
if (user.status.expires <= 10000) {
holder.messageTextView.setText(getStringEntry(R.string.Invisible));
} else {
int value = user.status.was_online;
if (value == 0) {
value = user.status.expires;
}
holder.messageTextView.setText(Utilities.formatDateOnline(value));
holder.messageTextView.setText(Utilities.formatDateOnline(user.status.expires));
}
holder.messageTextView.setTextColor(0xff808080);
}

View File

@ -25,7 +25,7 @@ import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.TextView;
import org.telegram.TL.TLRPC;
import org.telegram.messenger.TLRPC;
import org.telegram.messenger.FileLog;
import org.telegram.messenger.MessagesController;
import org.telegram.messenger.NotificationCenter;

View File

@ -22,7 +22,7 @@ import android.view.WindowManager;
import android.widget.LinearLayout;
import android.widget.TextView;
import org.telegram.TL.TLRPC;
import org.telegram.messenger.TLRPC;
import org.telegram.messenger.MessagesController;
import org.telegram.messenger.R;
import org.telegram.messenger.Utilities;

View File

@ -15,8 +15,9 @@ import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Parcelable;
import android.widget.Toast;
import org.telegram.TL.TLRPC;
import org.telegram.messenger.TLRPC;
import org.telegram.messenger.FileLog;
import org.telegram.messenger.MessagesController;
import org.telegram.messenger.NotificationCenter;
@ -25,6 +26,8 @@ import org.telegram.messenger.UserConfig;
import org.telegram.messenger.Utilities;
import org.telegram.ui.Views.PausableActivity;
import java.util.ArrayList;
public class LaunchActivity extends PausableActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@ -46,63 +49,77 @@ public class LaunchActivity extends PausableActivity {
Intent intent = getIntent();
if (intent != null && intent.getAction() != null) {
if (Intent.ACTION_SEND.equals(intent.getAction())) {
if (intent.getType() != null) {
if (intent.getType().startsWith("image/")) {
Parcelable parcelable = intent.getParcelableExtra(Intent.EXTRA_STREAM);
if (parcelable == null) {
return;
}
String path = null;
if (parcelable instanceof Uri) {
path = Utilities.getPath((Uri)parcelable);
} else {
path = intent.getParcelableExtra(Intent.EXTRA_STREAM).toString();
if (path.startsWith("content:")) {
Cursor cursor = getContentResolver().query(Uri.parse(path), new String[]{android.provider.MediaStore.Images.ImageColumns.DATA}, null, null, null);
if (cursor != null) {
cursor.moveToFirst();
path = cursor.getString(0);
cursor.close();
}
}
}
if (path != null) {
if (path.startsWith("file:")) {
path = path.replace("file://", "");
}
NotificationCenter.Instance.addToMemCache(533, path);
}
} else if (intent.getType().startsWith("video/")) {
Parcelable parcelable = intent.getParcelableExtra(Intent.EXTRA_STREAM);
if (parcelable == null) {
return;
}
String path = null;
if (parcelable instanceof Uri) {
path = Utilities.getPath((Uri)parcelable);
} else {
path = parcelable.toString();
if (path.startsWith("content:")) {
Cursor cursor = getContentResolver().query(Uri.parse(path), new String[]{android.provider.MediaStore.Images.ImageColumns.DATA}, null, null, null);
if (cursor != null) {
cursor.moveToFirst();
path = cursor.getString(0);
cursor.close();
}
}
}
if (path != null) {
if (path.startsWith("file:")) {
path = path.replace("file://", "");
}
NotificationCenter.Instance.addToMemCache(534, path);
}
} else if (intent.getType().equals("text/plain")) {
String text = intent.getStringExtra(Intent.EXTRA_TEXT);
if (text != null && text.length() != 0) {
NotificationCenter.Instance.addToMemCache(535, text);
}
boolean error = false;
String type = intent.getType();
if (type != null && type.equals("text/plain")) {
String text = intent.getStringExtra(Intent.EXTRA_TEXT);
if (text != null && text.length() != 0) {
NotificationCenter.Instance.addToMemCache(535, text);
} else {
error = true;
}
} else {
Parcelable parcelable = intent.getParcelableExtra(Intent.EXTRA_STREAM);
if (parcelable == null) {
return;
}
String path = null;
if (!(parcelable instanceof Uri)) {
parcelable = Uri.parse(parcelable.toString());
}
path = Utilities.getPath((Uri)parcelable);
if (path != null) {
if (path.startsWith("file:")) {
path = path.replace("file://", "");
}
if (type != null && type.startsWith("image/")) {
NotificationCenter.Instance.addToMemCache(533, path);
} else if (type != null && type.startsWith("video/")) {
NotificationCenter.Instance.addToMemCache(534, path);
} else {
NotificationCenter.Instance.addToMemCache(536, path);
}
} else {
error = true;
}
if (error) {
Toast.makeText(this, "Unsupported content", Toast.LENGTH_SHORT).show();
}
}
} else if (intent.getAction().equals(Intent.ACTION_SEND_MULTIPLE)) {
boolean error = false;
try {
ArrayList<Parcelable> uris = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM);
String type = intent.getType();
if (uris != null) {
String[] uris2 = new String[uris.size()];
for (int i = 0; i < uris2.length; i++) {
Parcelable parcelable = uris.get(i);
if (!(parcelable instanceof Uri)) {
parcelable = Uri.parse(parcelable.toString());
}
String path = Utilities.getPath((Uri)parcelable);
if (path != null) {
if (path.startsWith("file:")) {
path = path.replace("file://", "");
}
uris2[i] = path;
}
}
if (type != null && type.startsWith("image/")) {
NotificationCenter.Instance.addToMemCache(537, uris2);
} else {
NotificationCenter.Instance.addToMemCache(538, uris2);
}
} else {
error = true;
}
} catch (Exception e) {
FileLog.e("tmessages", e);
error = true;
}
if (error) {
Toast.makeText(this, "Unsupported content", Toast.LENGTH_SHORT).show();
}
} else if (Intent.ACTION_VIEW.equals(intent.getAction())) {
try {

View File

@ -28,7 +28,7 @@ import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import org.telegram.TL.TLRPC;
import org.telegram.messenger.TLRPC;
import org.telegram.objects.MessageObject;
import org.telegram.messenger.MessagesController;
import org.telegram.messenger.NotificationCenter;

View File

@ -26,8 +26,8 @@ import android.widget.EditText;
import android.widget.TextView;
import org.telegram.PhoneFormat.PhoneFormat;
import org.telegram.TL.TLObject;
import org.telegram.TL.TLRPC;
import org.telegram.messenger.TLObject;
import org.telegram.messenger.TLRPC;
import org.telegram.messenger.ConnectionsManager;
import org.telegram.messenger.FileLog;
import org.telegram.messenger.R;
@ -327,6 +327,7 @@ public class LoginActivityPhoneView extends SlideView implements AdapterView.OnI
if (error == null) {
final TLRPC.TL_auth_sentCode res = (TLRPC.TL_auth_sentCode)response;
params.putString("phoneHash", res.phone_code_hash);
params.putInt("calltime", res.send_call_timeout * 1000);
if (res.phone_registered) {
params.putString("registered", "true");
}

View File

@ -19,8 +19,8 @@ import android.view.inputmethod.EditorInfo;
import android.widget.EditText;
import android.widget.TextView;
import org.telegram.TL.TLObject;
import org.telegram.TL.TLRPC;
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;

View File

@ -21,8 +21,8 @@ import android.widget.EditText;
import android.widget.TextView;
import org.telegram.PhoneFormat.PhoneFormat;
import org.telegram.TL.TLObject;
import org.telegram.TL.TLRPC;
import org.telegram.messenger.TLObject;
import org.telegram.messenger.TLRPC;
import org.telegram.messenger.ConnectionsManager;
import org.telegram.messenger.ContactsController;
import org.telegram.messenger.FileLog;
@ -53,6 +53,7 @@ public class LoginActivitySmsView extends SlideView implements NotificationCente
private int time = 60000;
private double lastCurrentTime;
private boolean waitingForSms = false;
private int callTime = 60000;
public LoginActivitySmsView(Context context) {
super(context);
@ -113,6 +114,7 @@ public class LoginActivitySmsView extends SlideView implements NotificationCente
requestPhone = params.getString("phoneFormated");
phoneHash = params.getString("phoneHash");
registered = params.getString("registered");
callTime = params.getInt("calltime");
String number = PhoneFormat.Instance.format(phone);
confirmTextView.setText(Html.fromHtml(String.format(ApplicationLoader.applicationContext.getResources().getString(R.string.SentSmsCode) + " <b>%s</b>", number)));
@ -120,7 +122,7 @@ public class LoginActivitySmsView extends SlideView implements NotificationCente
Utilities.showKeyboard(codeField);
codeField.requestFocus();
time = 60000;
time = callTime;
try {
synchronized(timerSync) {
if (timeTimer != null) {

View File

@ -27,7 +27,7 @@ import android.widget.BaseAdapter;
import android.widget.GridView;
import android.widget.TextView;
import org.telegram.TL.TLRPC;
import org.telegram.messenger.TLRPC;
import org.telegram.messenger.Utilities;
import org.telegram.objects.MessageObject;
import org.telegram.messenger.MessagesController;
@ -288,24 +288,27 @@ public class MediaActivity extends BaseFragment implements NotificationCenter.No
obs.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
WindowManager manager = (WindowManager)parentActivity.getSystemService(Activity.WINDOW_SERVICE);
int rotation = manager.getDefaultDisplay().getRotation();
if (parentActivity != null) {
WindowManager manager = (WindowManager)parentActivity.getSystemService(Activity.WINDOW_SERVICE);
int rotation = manager.getDefaultDisplay().getRotation();
if (rotation == Surface.ROTATION_270 || rotation == Surface.ROTATION_90) {
orientation = 1;
listView.setNumColumns(6);
itemWidth = getResources().getDisplayMetrics().widthPixels / 6 - Utilities.dp(2) * 5;
listView.setColumnWidth(itemWidth);
} else {
orientation = 0;
listView.setNumColumns(4);
itemWidth = getResources().getDisplayMetrics().widthPixels / 4 - Utilities.dp(2) * 3;
listView.setColumnWidth(itemWidth);
if (rotation == Surface.ROTATION_270 || rotation == Surface.ROTATION_90) {
orientation = 1;
listView.setNumColumns(6);
itemWidth = getResources().getDisplayMetrics().widthPixels / 6 - Utilities.dp(2) * 5;
listView.setColumnWidth(itemWidth);
} else {
orientation = 0;
listView.setNumColumns(4);
itemWidth = getResources().getDisplayMetrics().widthPixels / 4 - Utilities.dp(2) * 3;
listView.setColumnWidth(itemWidth);
}
listView.setPadding(listView.getPaddingLeft(), Utilities.dp(4), listView.getPaddingRight(), listView.getPaddingBottom());
listAdapter.notifyDataSetChanged();
}
if (listView != null) {
listView.getViewTreeObserver().removeOnPreDrawListener(this);
}
listView.setPadding(listView.getPaddingLeft(), Utilities.dp(4), listView.getPaddingRight(), listView.getPaddingBottom());
listAdapter.notifyDataSetChanged();
listView.getViewTreeObserver().removeOnPreDrawListener(this);
return false;
}

View File

@ -30,8 +30,8 @@ import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import org.telegram.TL.TLObject;
import org.telegram.TL.TLRPC;
import org.telegram.messenger.TLObject;
import org.telegram.messenger.TLRPC;
import org.telegram.messenger.ContactsController;
import org.telegram.messenger.FileLog;
import org.telegram.messenger.MessagesController;
@ -121,6 +121,9 @@ public class MessagesActivity extends BaseFragment implements NotificationCenter
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
if (fragmentView == null) {
searching = false;
searchWas = false;
fragmentView = inflater.inflate(R.layout.messages_list, container, false);
messagesListViewAdapter = new MessagesAdapter(parentActivity);

View File

@ -10,6 +10,7 @@ package org.telegram.ui;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
@ -19,6 +20,7 @@ import android.net.Uri;
import android.os.Bundle;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarActivity;
import android.util.Base64;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
@ -32,8 +34,10 @@ import android.widget.TextView;
import android.widget.Toast;
import org.telegram.PhoneFormat.PhoneFormat;
import org.telegram.TL.TLObject;
import org.telegram.TL.TLRPC;
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;
@ -70,6 +74,7 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter
int askQuestionRow;
int logoutRow;
int sendLogsRow;
int clearLogsRow;
int rowCount;
int messagesSectionRow;
int sendByEnterRow;
@ -159,6 +164,7 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter
supportSectionRow = rowCount++;
if (ConnectionsManager.DEBUG_VERSION) {
sendLogsRow = rowCount++;
clearLogsRow = rowCount++;
}
askQuestionRow = rowCount++;
logoutRow = rowCount++;
@ -198,6 +204,7 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE);
SharedPreferences.Editor editor = preferences.edit();
editor.putInt("fons_size", 12 + which);
MessagesController.Instance.fontSize = 12 + which;
editor.commit();
if (listView != null) {
listView.invalidateViews();
@ -222,13 +229,92 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter
} else if (i == backgroundRow) {
((ApplicationActivity)parentActivity).presentFragment(new SettingsWallpapersActivity(), "settings_wallpapers", false);
} else if (i == askQuestionRow) {
ChatActivity fragment = new ChatActivity();
Bundle bundle = new Bundle();
bundle.putInt("user_id", 333000);
fragment.setArguments(bundle);
((ApplicationActivity)parentActivity).presentFragment(fragment, "chat" + Math.random(), false);
final SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE);
int uid = preferences.getInt("support_id", 0);
TLRPC.User supportUser = null;
if (uid != 0) {
supportUser = MessagesController.Instance.users.get(uid);
if (supportUser == null) {
String userString = preferences.getString("support_user", null);
if (userString != null) {
try {
byte[] datacentersBytes = Base64.decode(userString, Base64.DEFAULT);
if (datacentersBytes != null) {
SerializedData data = new SerializedData(datacentersBytes);
supportUser = (TLRPC.User)TLClassStore.Instance().TLdeserialize(data, data.readInt32());
}
} catch (Exception e) {
FileLog.e("tmessages", e);
supportUser = null;
}
}
}
}
if (supportUser == null) {
if (parentActivity == null) {
return;
}
final ProgressDialog progressDialog = new ProgressDialog(parentActivity);
progressDialog.setMessage(parentActivity.getString(R.string.Loading));
progressDialog.setCanceledOnTouchOutside(false);
progressDialog.setCancelable(false);
progressDialog.show();
TLRPC.TL_help_getSupport req = new TLRPC.TL_help_getSupport();
ConnectionsManager.Instance.performRpc(req, new RPCRequest.RPCRequestDelegate() {
@Override
public void run(TLObject response, TLRPC.TL_error error) {
if (error == null) {
final TLRPC.TL_help_support res = (TLRPC.TL_help_support)response;
Utilities.RunOnUIThread(new Runnable() {
@Override
public void run() {
SharedPreferences.Editor editor = preferences.edit();
editor.putInt("support_id", res.user.id);
SerializedData data = new SerializedData();
res.user.serializeToStream(data);
editor.putString("support_user", Base64.encodeToString(data.toByteArray(), Base64.DEFAULT));
editor.commit();
try {
progressDialog.dismiss();
} catch (Exception e) {
FileLog.e("tmessages", e);
}
MessagesController.Instance.users.put(res.user.id, res.user);
ChatActivity fragment = new ChatActivity();
Bundle bundle = new Bundle();
bundle.putInt("user_id", res.user.id);
fragment.setArguments(bundle);
((ApplicationActivity)parentActivity).presentFragment(fragment, "chat" + Math.random(), false);
}
});
} else {
Utilities.RunOnUIThread(new Runnable() {
@Override
public void run() {
try {
progressDialog.dismiss();
} catch (Exception e) {
FileLog.e("tmessages", e);
}
}
});
}
}
}, null, true, RPCRequest.RPCRequestClassGeneric);
} else {
MessagesController.Instance.users.putIfAbsent(supportUser.id, supportUser);
ChatActivity fragment = new ChatActivity();
Bundle bundle = new Bundle();
bundle.putInt("user_id", supportUser.id);
fragment.setArguments(bundle);
((ApplicationActivity)parentActivity).presentFragment(fragment, "chat" + Math.random(), false);
}
} else if (i == sendLogsRow) {
sendLogs();
} else if (i == clearLogsRow) {
FileLog.cleanupLogs();
} else if (i == sendByEnterRow) {
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE);
boolean send = preferences.getBoolean("send_by_enter", false);
@ -314,11 +400,7 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 232) {
FileLog.cleanupLogs();
} else {
avatarUpdater.onActivityResult(requestCode, resultCode, data);
}
avatarUpdater.onActivityResult(requestCode, resultCode, data);
}
@Override
@ -377,7 +459,7 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter
i.putExtra(Intent.EXTRA_EMAIL, new String[]{"drklo.2kb@gmail.com"});
i.putExtra(Intent.EXTRA_SUBJECT, "last logs");
i.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris);
startActivityForResult(Intent.createChooser(i, "Select email application."), 232);
startActivity(Intent.createChooser(i, "Select email application."));
} catch (Exception e) {
e.printStackTrace();
}
@ -427,7 +509,7 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter
public boolean isEnabled(int i) {
return i == textSizeRow || i == enableAnimationsRow || i == blockedRow || i == notificationRow || i == backgroundRow ||
i == askQuestionRow || i == sendLogsRow || i == sendByEnterRow || i == terminateSessionsRow || i == photoDownloadPrivateRow ||
i == photoDownloadChatRow;
i == photoDownloadChatRow || i == clearLogsRow;
}
@Override
@ -619,6 +701,9 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter
} else if (i == sendLogsRow) {
textView.setText("Send Logs");
divider.setVisibility(View.VISIBLE);
} else if (i == clearLogsRow) {
textView.setText("Clear Logs");
divider.setVisibility(View.VISIBLE);
} else if (i == askQuestionRow) {
textView.setText(getStringEntry(R.string.AskAQuestion));
divider.setVisibility(View.INVISIBLE);
@ -738,7 +823,7 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter
return 5;
} else if (i == enableAnimationsRow || i == sendByEnterRow || i == photoDownloadChatRow || i == photoDownloadPrivateRow) {
return 3;
} else if (i == numberRow || i == notificationRow || i == blockedRow || i == backgroundRow || i == askQuestionRow || i == sendLogsRow || i == terminateSessionsRow) {
} else if (i == numberRow || i == notificationRow || i == blockedRow || i == backgroundRow || i == askQuestionRow || i == sendLogsRow || i == terminateSessionsRow || i == clearLogsRow) {
return 2;
} else if (i == logoutRow) {
return 4;

View File

@ -25,8 +25,8 @@ import android.widget.ListView;
import android.widget.TextView;
import org.telegram.PhoneFormat.PhoneFormat;
import org.telegram.TL.TLObject;
import org.telegram.TL.TLRPC;
import org.telegram.messenger.TLObject;
import org.telegram.messenger.TLRPC;
import org.telegram.messenger.ConnectionsManager;
import org.telegram.messenger.MessagesController;
import org.telegram.messenger.NotificationCenter;

View File

@ -16,15 +16,14 @@ import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.inputmethod.EditorInfo;
import android.widget.EditText;
import android.widget.TextView;
import org.telegram.TL.TLObject;
import org.telegram.TL.TLRPC;
import org.telegram.messenger.TLObject;
import org.telegram.messenger.TLRPC;
import org.telegram.messenger.ConnectionsManager;
import org.telegram.messenger.MessagesController;
import org.telegram.messenger.NotificationCenter;

View File

@ -30,8 +30,8 @@ import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import org.telegram.TL.TLObject;
import org.telegram.TL.TLRPC;
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;

View File

@ -29,8 +29,8 @@ import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ProgressBar;
import org.telegram.TL.TLObject;
import org.telegram.TL.TLRPC;
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;
@ -356,6 +356,9 @@ public class SettingsWallpapersActivity extends BaseFragment implements Notifica
long reqId = ConnectionsManager.Instance.performRpc(req, new RPCRequest.RPCRequestDelegate() {
@Override
public void run(final TLObject response, TLRPC.TL_error error) {
if (error != null) {
return;
}
Utilities.RunOnUIThread(new Runnable() {
@Override
public void run() {

View File

@ -37,8 +37,8 @@ import android.widget.ListView;
import android.widget.TextView;
import org.telegram.PhoneFormat.PhoneFormat;
import org.telegram.TL.TLObject;
import org.telegram.TL.TLRPC;
import org.telegram.messenger.TLObject;
import org.telegram.messenger.TLRPC;
import org.telegram.messenger.ConnectionsManager;
import org.telegram.messenger.ContactsController;
import org.telegram.messenger.FileLog;
@ -632,17 +632,13 @@ public class UserProfileActivity extends BaseFragment implements NotificationCen
onlineText.setText(getStringEntry(R.string.Offline));
} else {
int currentTime = ConnectionsManager.Instance.getCurrentTime();
if (user.status.expires > currentTime || user.status.was_online > currentTime) {
if (user.status.expires > currentTime) {
onlineText.setText(getStringEntry(R.string.Online));
} else {
if (user.status.was_online <= 10000 && user.status.expires <= 10000) {
if (user.status.expires <= 10000) {
onlineText.setText(getStringEntry(R.string.Invisible));
} else {
int value = user.status.was_online;
if (value == 0) {
value = user.status.expires;
}
onlineText.setText(Utilities.formatDateOnline(value));
onlineText.setText(Utilities.formatDateOnline(user.status.expires));
}
}
}
@ -722,6 +718,9 @@ public class UserProfileActivity extends BaseFragment implements NotificationCen
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (parentActivity == null) {
return;
}
TLRPC.User user = MessagesController.Instance.users.get(user_id);
if (user == null || user instanceof TLRPC.TL_userEmpty) {
return;

View File

@ -15,7 +15,7 @@ import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import org.telegram.TL.TLRPC;
import org.telegram.messenger.TLRPC;
import org.telegram.messenger.FileLoader;
import org.telegram.messenger.FileLog;
import org.telegram.messenger.NotificationCenter;

View File

@ -16,7 +16,7 @@ import android.graphics.drawable.NinePatchDrawable;
import android.os.Build;
import android.widget.ImageView;
import org.telegram.TL.TLRPC;
import org.telegram.messenger.TLRPC;
import org.telegram.messenger.FileLoader;
import org.telegram.messenger.FileLog;
import org.telegram.messenger.Utilities;

View File

@ -15,7 +15,7 @@ import android.graphics.drawable.Drawable;
import android.os.Build;
import android.view.View;
import org.telegram.TL.TLRPC;
import org.telegram.messenger.TLRPC;
import org.telegram.messenger.FileLoader;
import org.telegram.messenger.FileLog;
import org.telegram.messenger.Utilities;

View File

@ -1,69 +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.view.View;
import android.widget.TextView;
import org.telegram.messenger.R;
import org.telegram.messenger.Utilities;
public class MessageLayout extends FrameLayoutFixed {
public TextView timeTextView;
public View timeLayout;
public TightTextView messageTextView;
public int maxWidth;
public MessageLayout(android.content.Context context) {
super(context);
}
public MessageLayout(android.content.Context context, android.util.AttributeSet attrs) {
super(context, attrs);
}
public MessageLayout(android.content.Context context, android.util.AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int timeWidth = timeLayout != null ? timeLayout.getMeasuredWidth() : timeTextView.getMeasuredWidth();
int totalWidth = getMeasuredWidth();
int maxChildWidth = getChildAt(0).getMeasuredWidth();
int count = getChildCount();
for (int a = 1; a < count - 1; a++) {
maxChildWidth = Math.max(maxChildWidth, getChildAt(a).getMeasuredWidth());
}
int timeMore = timeWidth + Utilities.dp(6);
int fields = totalWidth - Math.max(maxChildWidth, timeWidth);
int height = getMeasuredHeight();
if (maxWidth - messageTextView.lastLineWidth < timeMore) {
setMeasuredDimension(Math.max(maxChildWidth, messageTextView.lastLineWidth) + fields, height + Utilities.dp(14));
} else {
int diff = maxChildWidth - messageTextView.lastLineWidth;
if (diff >= 0 && diff <= timeMore) {
setMeasuredDimension(maxChildWidth + timeMore - diff + fields, height);
} else {
setMeasuredDimension(Math.max(maxChildWidth, messageTextView.lastLineWidth + timeMore) + fields, height);
}
}
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
timeTextView = (TextView)findViewById(R.id.chat_time_text);
messageTextView = (TightTextView)findViewById(R.id.chat_message_text);
timeLayout = findViewById(R.id.chat_time_layout);
}
}

View File

@ -23,7 +23,7 @@ import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import org.telegram.TL.TLRPC;
import org.telegram.messenger.TLRPC;
import org.telegram.messenger.FileLog;
import org.telegram.messenger.MessagesController;
import org.telegram.messenger.NotificationCenter;

View File

@ -0,0 +1,63 @@
/*
* This is the source code of Telegram for Android v. 1.3.x.
* It is licensed under GNU GPL v. 2 or later.
* You should have received a copy of the license in this archive (see LICENSE).
*
* Copyright Nikolai Kudashov, 2013-2014.
*/
package org.telegram.ui.Views;
import android.graphics.Canvas;
import android.graphics.Paint;
import org.telegram.messenger.Utilities;
public class ProgressView {
private static Paint innerPaint1;
private static Paint outerPaint1;
private static Paint innerPaint2;
private static Paint outerPaint2;
public int type;
public int thumbX = 0;
public int width;
public int height;
public ProgressView() {
if (innerPaint1 == null) {
innerPaint1 = new Paint();
outerPaint1 = new Paint();
innerPaint2 = new Paint();
outerPaint2 = new Paint();
innerPaint1.setColor(0xffb4e396);
outerPaint1.setColor(0xff6ac453);
innerPaint2.setColor(0xffd9e2eb);
outerPaint2.setColor(0xff86c5f8);
}
}
public void setProgress(float progress) {
thumbX = (int)Math.ceil(width * progress);
if (thumbX < 0) {
thumbX = 0;
} else if (thumbX > width) {
thumbX = width;
}
}
public void draw(Canvas canvas) {
Paint inner = null;
Paint outer = null;
if (type == 0) {
inner = innerPaint1;
outer = outerPaint1;
} else if (type == 1) {
inner = innerPaint2;
outer = outerPaint2;
}
canvas.drawRect(0, height / 2 - Utilities.dp(1), width, height / 2 + Utilities.dp(1), inner);
canvas.drawRect(0, height / 2 - Utilities.dp(1), thumbX, height / 2 + Utilities.dp(1), outer);
}
}

View File

@ -13,7 +13,9 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
public abstract class SectionedBaseAdapter extends BaseAdapter implements PinnedHeaderListView.PinnedSectionedHeaderAdapter {
import org.telegram.ui.Adapters.BaseFragmentAdapter;
public abstract class SectionedBaseAdapter extends BaseFragmentAdapter implements PinnedHeaderListView.PinnedSectionedHeaderAdapter {
/**
* Holds the calculated values of @{link getPositionInSectionForPosition}

View File

@ -12,51 +12,41 @@ import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import org.telegram.messenger.R;
import org.telegram.messenger.Utilities;
public class SeekBar extends View {
Drawable thumbDrawable1;
Drawable thumbDrawablePressed1;
Drawable thumbDrawable2;
Drawable thumbDrawablePressed2;
static Paint innerPaint1 = new Paint();
static Paint outerPaint1 = new Paint();
static Paint innerPaint2 = new Paint();
static Paint outerPaint2 = new Paint();
public class SeekBar {
public abstract interface SeekBarDelegate {
public void onSeekBarDrag(float progress);
}
private static Drawable thumbDrawable1;
private static Drawable thumbDrawablePressed1;
private static Drawable thumbDrawable2;
private static Drawable thumbDrawablePressed2;
private static Paint innerPaint1 = new Paint();
private static Paint outerPaint1 = new Paint();
private static Paint innerPaint2 = new Paint();
private static Paint outerPaint2 = new Paint();
private static int thumbWidth;
private static int thumbHeight;
public int type;
public int thumbX = 0;
public int thumbDX = 0;
private boolean pressed = false;
private boolean dragging = false;
private int thumbWidth;
private int thumbHeight;
public int width;
public int height;
public SeekBarDelegate delegate;
public SeekBar(Context context) {
super(context);
init();
}
public SeekBar(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public SeekBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
if (thumbDrawable1 == null) {
thumbDrawable1 = getResources().getDrawable(R.drawable.player1);
thumbDrawablePressed1 = getResources().getDrawable(R.drawable.player1_pressed);
thumbDrawable2 = getResources().getDrawable(R.drawable.player2);
thumbDrawablePressed2 = getResources().getDrawable(R.drawable.player2_pressed);
thumbDrawable1 = context.getResources().getDrawable(R.drawable.player1);
thumbDrawablePressed1 = context.getResources().getDrawable(R.drawable.player1_pressed);
thumbDrawable2 = context.getResources().getDrawable(R.drawable.player2);
thumbDrawablePressed2 = context.getResources().getDrawable(R.drawable.player2_pressed);
innerPaint1.setColor(0xffb4e396);
outerPaint1.setColor(0xff6ac453);
innerPaint2.setColor(0xffd9e2eb);
@ -64,46 +54,52 @@ public class SeekBar extends View {
thumbWidth = thumbDrawable1.getIntrinsicWidth();
thumbHeight = thumbDrawable1.getIntrinsicHeight();
}
setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
float x = motionEvent.getX();
float y = motionEvent.getY();
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
int additionWidth = (getMeasuredHeight() - thumbWidth) / 2;
if (thumbX - additionWidth <= x && x <= thumbX + thumbWidth + additionWidth && y >= 0 && y <= getMeasuredHeight()) {
pressed = true;
thumbDX = (int)(x - thumbX);
invalidate();
getParent().requestDisallowInterceptTouchEvent(true);
return true;
}
} else if (motionEvent.getAction() == MotionEvent.ACTION_UP || motionEvent.getAction() == MotionEvent.ACTION_CANCEL) {
if (pressed) {
pressed = false;
invalidate();
return true;
}
} else if (motionEvent.getAction() == MotionEvent.ACTION_MOVE) {
if (pressed) {
thumbX = (int)(x - thumbDX);
if (thumbX < 0) {
thumbX = 0;
} else if (thumbX > getMeasuredWidth() - thumbWidth) {
thumbX = getMeasuredWidth() - thumbWidth;
}
invalidate();
return true;
}
}
return false;
}
});
}
@Override
protected void onDraw(Canvas canvas) {
public boolean onTouch(int action, float x, float y) {
if (action == MotionEvent.ACTION_DOWN) {
int additionWidth = (height - thumbWidth) / 2;
if (thumbX - additionWidth <= x && x <= thumbX + thumbWidth + additionWidth && y >= 0 && y <= height) {
pressed = true;
thumbDX = (int)(x - thumbX);
return true;
}
} else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
if (pressed) {
if (action == MotionEvent.ACTION_UP && delegate != null) {
delegate.onSeekBarDrag((float)thumbX / (float)(width - thumbWidth));
}
pressed = false;
return true;
}
} else if (action == MotionEvent.ACTION_MOVE) {
if (pressed) {
thumbX = (int)(x - thumbDX);
if (thumbX < 0) {
thumbX = 0;
} else if (thumbX > width - thumbWidth) {
thumbX = width - thumbWidth;
}
return true;
}
}
return false;
}
public void setProgress(float progress) {
thumbX = (int)Math.ceil((width - thumbWidth) * progress);
if (thumbX < 0) {
thumbX = 0;
} else if (thumbX > width - thumbWidth) {
thumbX = width - thumbWidth;
}
}
public boolean isDragging() {
return pressed;
}
public void draw(Canvas canvas) {
Drawable thumb = null;
Paint inner = null;
Paint outer = null;
@ -124,8 +120,6 @@ public class SeekBar extends View {
inner = innerPaint2;
outer = outerPaint2;
}
int height = getMeasuredHeight();
int width = getMeasuredWidth();
int y = (height - thumbHeight) / 2;
canvas.drawRect(thumbWidth / 2, height / 2 - Utilities.dp(1), width - thumbWidth / 2, height / 2 + Utilities.dp(1), inner);
canvas.drawRect(thumbWidth / 2, height / 2 - Utilities.dp(1), thumbWidth / 2 + thumbX, height / 2 + Utilities.dp(1), outer);

Binary file not shown.

After

Width:  |  Height:  |  Size: 438 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 441 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 439 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 443 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 229 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 229 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 229 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 229 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 283 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 283 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 283 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 287 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 179 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 179 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 179 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 179 B

Some files were not shown because too many files have changed in this diff Show More