1
0
mirror of https://github.com/MGislv/NekoX.git synced 2024-07-02 10:33:36 +00:00

Bug fixes

This commit is contained in:
DrKLO 2014-10-28 20:07:44 +03:00
parent 3cd9b847e1
commit a4af1fb2f7
16 changed files with 7279 additions and 4303 deletions

View File

@ -80,7 +80,7 @@ android {
defaultConfig { defaultConfig {
minSdkVersion 8 minSdkVersion 8
targetSdkVersion 19 targetSdkVersion 19
versionCode 374 versionCode 377
versionName "1.9.6" versionName "1.9.7"
} }
} }

View File

@ -5,7 +5,7 @@ LOCAL_PRELINK_MODULE := false
LOCAL_MODULE := tmessages.1 LOCAL_MODULE := tmessages.1
LOCAL_CFLAGS := -w -std=gnu99 -O2 -DNULL=0 -DSOCKLEN_T=socklen_t -DLOCALE_NOT_USED -D_LARGEFILE_SOURCE=1 -D_FILE_OFFSET_BITS=64 LOCAL_CFLAGS := -w -std=gnu99 -O2 -DNULL=0 -DSOCKLEN_T=socklen_t -DLOCALE_NOT_USED -D_LARGEFILE_SOURCE=1 -D_FILE_OFFSET_BITS=64
LOCAL_CFLAGS += -Drestrict='' -D__EMX__ -DOPUS_BUILD -DFIXED_POINT -DUSE_ALLOCA -DHAVE_LRINT -DHAVE_LRINTF -fno-math-errno LOCAL_CFLAGS += -Drestrict='' -D__EMX__ -DOPUS_BUILD -DFIXED_POINT -DUSE_ALLOCA -DHAVE_LRINT -DHAVE_LRINTF -fno-math-errno
LOCAL_CFLAGS += -DANDROID_NDK -DDISABLE_IMPORTGL -fno-strict-aliasing -fprefetch-loop-arrays -DAVOID_TABLES -DANDROID_TILE_BASED_DECODE -DANDROID_ARMV6_IDCT LOCAL_CFLAGS += -DANDROID_NDK -DDISABLE_IMPORTGL -fno-strict-aliasing -fprefetch-loop-arrays -DAVOID_TABLES -DANDROID_TILE_BASED_DECODE -DANDROID_ARMV6_IDCT -DHAVE_STRCHRNUL=0
LOCAL_CPPFLAGS := -DBSD=1 -ffast-math -O2 -funroll-loops LOCAL_CPPFLAGS := -DBSD=1 -ffast-math -O2 -funroll-loops
#LOCAL_LDLIBS := -llog #LOCAL_LDLIBS := -llog
LOCAL_LDLIBS := -ljnigraphics -llog LOCAL_LDLIBS := -ljnigraphics -llog

File diff suppressed because it is too large Load Diff

View File

@ -107,9 +107,9 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()]. ** [sqlite_version()] and [sqlite_source_id()].
*/ */
#define SQLITE_VERSION "3.8.6" #define SQLITE_VERSION "3.8.7"
#define SQLITE_VERSION_NUMBER 3008006 #define SQLITE_VERSION_NUMBER 3008007
#define SQLITE_SOURCE_ID "2014-08-15 11:46:33 9491ba7d738528f168657adb43a198238abde19e" #define SQLITE_SOURCE_ID "2014-10-17 11:24:17 e4ab094f8afce0817f4074e823fabe59fc29ebb4"
/* /*
** CAPI3REF: Run-Time Library Version Numbers ** CAPI3REF: Run-Time Library Version Numbers
@ -497,6 +497,7 @@ SQLITE_API int sqlite3_exec(
#define SQLITE_NOTICE_RECOVER_WAL (SQLITE_NOTICE | (1<<8)) #define SQLITE_NOTICE_RECOVER_WAL (SQLITE_NOTICE | (1<<8))
#define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8)) #define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8))
#define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1<<8)) #define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1<<8))
#define SQLITE_AUTH_USER (SQLITE_AUTH | (1<<8))
/* /*
** CAPI3REF: Flags For File Open Operations ** CAPI3REF: Flags For File Open Operations
@ -2099,7 +2100,7 @@ SQLITE_API int sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*);
** turns off all busy handlers. ** turns off all busy handlers.
** **
** ^(There can only be a single busy handler for a particular ** ^(There can only be a single busy handler for a particular
** [database connection] any any given moment. If another busy handler ** [database connection] at any given moment. If another busy handler
** was defined (using [sqlite3_busy_handler()]) prior to calling ** was defined (using [sqlite3_busy_handler()]) prior to calling
** this routine, that other busy handler is cleared.)^ ** this routine, that other busy handler is cleared.)^
** **
@ -2303,6 +2304,10 @@ SQLITE_API char *sqlite3_vsnprintf(int,char*,const char*, va_list);
** sqlite3_malloc() is zero or negative then sqlite3_malloc() returns ** sqlite3_malloc() is zero or negative then sqlite3_malloc() returns
** a NULL pointer. ** a NULL pointer.
** **
** ^The sqlite3_malloc64(N) routine works just like
** sqlite3_malloc(N) except that N is an unsigned 64-bit integer instead
** of a signed 32-bit integer.
**
** ^Calling sqlite3_free() with a pointer previously returned ** ^Calling sqlite3_free() with a pointer previously returned
** by sqlite3_malloc() or sqlite3_realloc() releases that memory so ** by sqlite3_malloc() or sqlite3_realloc() releases that memory so
** that it might be reused. ^The sqlite3_free() routine is ** that it might be reused. ^The sqlite3_free() routine is
@ -2314,24 +2319,38 @@ SQLITE_API char *sqlite3_vsnprintf(int,char*,const char*, va_list);
** might result if sqlite3_free() is called with a non-NULL pointer that ** might result if sqlite3_free() is called with a non-NULL pointer that
** was not obtained from sqlite3_malloc() or sqlite3_realloc(). ** was not obtained from sqlite3_malloc() or sqlite3_realloc().
** **
** ^(The sqlite3_realloc() interface attempts to resize a ** ^The sqlite3_realloc(X,N) interface attempts to resize a
** prior memory allocation to be at least N bytes, where N is the ** prior memory allocation X to be at least N bytes.
** second parameter. The memory allocation to be resized is the first ** ^If the X parameter to sqlite3_realloc(X,N)
** parameter.)^ ^ If the first parameter to sqlite3_realloc()
** is a NULL pointer then its behavior is identical to calling ** is a NULL pointer then its behavior is identical to calling
** sqlite3_malloc(N) where N is the second parameter to sqlite3_realloc(). ** sqlite3_malloc(N).
** ^If the second parameter to sqlite3_realloc() is zero or ** ^If the N parameter to sqlite3_realloc(X,N) is zero or
** negative then the behavior is exactly the same as calling ** negative then the behavior is exactly the same as calling
** sqlite3_free(P) where P is the first parameter to sqlite3_realloc(). ** sqlite3_free(X).
** ^sqlite3_realloc() returns a pointer to a memory allocation ** ^sqlite3_realloc(X,N) returns a pointer to a memory allocation
** of at least N bytes in size or NULL if sufficient memory is unavailable. ** of at least N bytes in size or NULL if insufficient memory is available.
** ^If M is the size of the prior allocation, then min(N,M) bytes ** ^If M is the size of the prior allocation, then min(N,M) bytes
** of the prior allocation are copied into the beginning of buffer returned ** of the prior allocation are copied into the beginning of buffer returned
** by sqlite3_realloc() and the prior allocation is freed. ** by sqlite3_realloc(X,N) and the prior allocation is freed.
** ^If sqlite3_realloc() returns NULL, then the prior allocation ** ^If sqlite3_realloc(X,N) returns NULL and N is positive, then the
** is not freed. ** prior allocation is not freed.
** **
** ^The memory returned by sqlite3_malloc() and sqlite3_realloc() ** ^The sqlite3_realloc64(X,N) interfaces works the same as
** sqlite3_realloc(X,N) except that N is a 64-bit unsigned integer instead
** of a 32-bit signed integer.
**
** ^If X is a memory allocation previously obtained from sqlite3_malloc(),
** sqlite3_malloc64(), sqlite3_realloc(), or sqlite3_realloc64(), then
** sqlite3_msize(X) returns the size of that memory allocation in bytes.
** ^The value returned by sqlite3_msize(X) might be larger than the number
** of bytes requested when X was allocated. ^If X is a NULL pointer then
** sqlite3_msize(X) returns zero. If X points to something that is not
** the beginning of memory allocation, or if it points to a formerly
** valid memory allocation that has now been freed, then the behavior
** of sqlite3_msize(X) is undefined and possibly harmful.
**
** ^The memory returned by sqlite3_malloc(), sqlite3_realloc(),
** sqlite3_malloc64(), and sqlite3_realloc64()
** is always aligned to at least an 8 byte boundary, or to a ** is always aligned to at least an 8 byte boundary, or to a
** 4 byte boundary if the [SQLITE_4_BYTE_ALIGNED_MALLOC] compile-time ** 4 byte boundary if the [SQLITE_4_BYTE_ALIGNED_MALLOC] compile-time
** option is used. ** option is used.
@ -2359,8 +2378,11 @@ SQLITE_API char *sqlite3_vsnprintf(int,char*,const char*, va_list);
** [sqlite3_free()] or [sqlite3_realloc()]. ** [sqlite3_free()] or [sqlite3_realloc()].
*/ */
SQLITE_API void *sqlite3_malloc(int); SQLITE_API void *sqlite3_malloc(int);
SQLITE_API void *sqlite3_malloc64(sqlite3_uint64);
SQLITE_API void *sqlite3_realloc(void*, int); SQLITE_API void *sqlite3_realloc(void*, int);
SQLITE_API void *sqlite3_realloc64(void*, sqlite3_uint64);
SQLITE_API void sqlite3_free(void*); SQLITE_API void sqlite3_free(void*);
SQLITE_API sqlite3_uint64 sqlite3_msize(void*);
/* /*
** CAPI3REF: Memory Allocator Statistics ** CAPI3REF: Memory Allocator Statistics
@ -2647,9 +2669,9 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
** an English language description of the error following a failure of any ** an English language description of the error following a failure of any
** of the sqlite3_open() routines. ** of the sqlite3_open() routines.
** **
** ^The default encoding for the database will be UTF-8 if ** ^The default encoding will be UTF-8 for databases created using
** sqlite3_open() or sqlite3_open_v2() is called and ** sqlite3_open() or sqlite3_open_v2(). ^The default encoding for databases
** UTF-16 in the native byte order if sqlite3_open16() is used. ** created using sqlite3_open16() will be UTF-16 in the native byte order.
** **
** Whether or not an error occurs when it is opened, resources ** Whether or not an error occurs when it is opened, resources
** associated with the [database connection] handle should be released by ** associated with the [database connection] handle should be released by
@ -2737,13 +2759,14 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
** then it is interpreted as an absolute path. ^If the path does not begin ** then it is interpreted as an absolute path. ^If the path does not begin
** with a '/' (meaning that the authority section is omitted from the URI) ** with a '/' (meaning that the authority section is omitted from the URI)
** then the path is interpreted as a relative path. ** then the path is interpreted as a relative path.
** ^On windows, the first component of an absolute path ** ^(On windows, the first component of an absolute path
** is a drive specification (e.g. "C:"). ** is a drive specification (e.g. "C:").)^
** **
** [[core URI query parameters]] ** [[core URI query parameters]]
** The query component of a URI may contain parameters that are interpreted ** The query component of a URI may contain parameters that are interpreted
** either by SQLite itself, or by a [VFS | custom VFS implementation]. ** either by SQLite itself, or by a [VFS | custom VFS implementation].
** SQLite interprets the following three query parameters: ** SQLite and its built-in [VFSes] interpret the
** following query parameters:
** **
** <ul> ** <ul>
** <li> <b>vfs</b>: ^The "vfs" parameter may be used to specify the name of ** <li> <b>vfs</b>: ^The "vfs" parameter may be used to specify the name of
@ -2778,11 +2801,9 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
** a URI filename, its value overrides any behavior requested by setting ** a URI filename, its value overrides any behavior requested by setting
** SQLITE_OPEN_PRIVATECACHE or SQLITE_OPEN_SHAREDCACHE flag. ** SQLITE_OPEN_PRIVATECACHE or SQLITE_OPEN_SHAREDCACHE flag.
** **
** <li> <b>psow</b>: ^The psow parameter may be "true" (or "on" or "yes" or ** <li> <b>psow</b>: ^The psow parameter indicates whether or not the
** "1") or "false" (or "off" or "no" or "0") to indicate that the
** [powersafe overwrite] property does or does not apply to the ** [powersafe overwrite] property does or does not apply to the
** storage media on which the database file resides. ^The psow query ** storage media on which the database file resides.
** parameter only works for the built-in unix and Windows VFSes.
** **
** <li> <b>nolock</b>: ^The nolock parameter is a boolean query parameter ** <li> <b>nolock</b>: ^The nolock parameter is a boolean query parameter
** which if set disables file locking in rollback journal modes. This ** which if set disables file locking in rollback journal modes. This
@ -3078,6 +3099,10 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
** **
** [[SQLITE_LIMIT_TRIGGER_DEPTH]] ^(<dt>SQLITE_LIMIT_TRIGGER_DEPTH</dt> ** [[SQLITE_LIMIT_TRIGGER_DEPTH]] ^(<dt>SQLITE_LIMIT_TRIGGER_DEPTH</dt>
** <dd>The maximum depth of recursion for triggers.</dd>)^ ** <dd>The maximum depth of recursion for triggers.</dd>)^
**
** [[SQLITE_LIMIT_WORKER_THREADS]] ^(<dt>SQLITE_LIMIT_WORKER_THREADS</dt>
** <dd>The maximum number of auxiliary worker threads that a single
** [prepared statement] may start.</dd>)^
** </dl> ** </dl>
*/ */
#define SQLITE_LIMIT_LENGTH 0 #define SQLITE_LIMIT_LENGTH 0
@ -3091,6 +3116,7 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
#define SQLITE_LIMIT_LIKE_PATTERN_LENGTH 8 #define SQLITE_LIMIT_LIKE_PATTERN_LENGTH 8
#define SQLITE_LIMIT_VARIABLE_NUMBER 9 #define SQLITE_LIMIT_VARIABLE_NUMBER 9
#define SQLITE_LIMIT_TRIGGER_DEPTH 10 #define SQLITE_LIMIT_TRIGGER_DEPTH 10
#define SQLITE_LIMIT_WORKER_THREADS 11
/* /*
** CAPI3REF: Compiling An SQL Statement ** CAPI3REF: Compiling An SQL Statement
@ -3364,18 +3390,18 @@ typedef struct sqlite3_context sqlite3_context;
** If the fourth parameter to sqlite3_bind_blob() is negative, then ** If the fourth parameter to sqlite3_bind_blob() is negative, then
** the behavior is undefined. ** the behavior is undefined.
** If a non-negative fourth parameter is provided to sqlite3_bind_text() ** If a non-negative fourth parameter is provided to sqlite3_bind_text()
** or sqlite3_bind_text16() then that parameter must be the byte offset ** or sqlite3_bind_text16() or sqlite3_bind_text64() then
** that parameter must be the byte offset
** where the NUL terminator would occur assuming the string were NUL ** where the NUL terminator would occur assuming the string were NUL
** terminated. If any NUL characters occur at byte offsets less than ** terminated. If any NUL characters occur at byte offsets less than
** the value of the fourth parameter then the resulting string value will ** the value of the fourth parameter then the resulting string value will
** contain embedded NULs. The result of expressions involving strings ** contain embedded NULs. The result of expressions involving strings
** with embedded NULs is undefined. ** with embedded NULs is undefined.
** **
** ^The fifth argument to sqlite3_bind_blob(), sqlite3_bind_text(), and ** ^The fifth argument to the BLOB and string binding interfaces
** sqlite3_bind_text16() is a destructor used to dispose of the BLOB or ** is a destructor used to dispose of the BLOB or
** string after SQLite has finished with it. ^The destructor is called ** string after SQLite has finished with it. ^The destructor is called
** to dispose of the BLOB or string even if the call to sqlite3_bind_blob(), ** to dispose of the BLOB or string even if the call to bind API fails.
** sqlite3_bind_text(), or sqlite3_bind_text16() fails.
** ^If the fifth argument is ** ^If the fifth argument is
** the special value [SQLITE_STATIC], then SQLite assumes that the ** the special value [SQLITE_STATIC], then SQLite assumes that the
** information is in static, unmanaged space and does not need to be freed. ** information is in static, unmanaged space and does not need to be freed.
@ -3383,6 +3409,14 @@ typedef struct sqlite3_context sqlite3_context;
** SQLite makes its own private copy of the data immediately, before ** SQLite makes its own private copy of the data immediately, before
** the sqlite3_bind_*() routine returns. ** the sqlite3_bind_*() routine returns.
** **
** ^The sixth argument to sqlite3_bind_text64() must be one of
** [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE]
** to specify the encoding of the text in the third parameter. If
** the sixth argument to sqlite3_bind_text64() is not one of the
** allowed values shown above, or if the text encoding is different
** from the encoding specified by the sixth parameter, then the behavior
** is undefined.
**
** ^The sqlite3_bind_zeroblob() routine binds a BLOB of length N that ** ^The sqlite3_bind_zeroblob() routine binds a BLOB of length N that
** is filled with zeroes. ^A zeroblob uses a fixed amount of memory ** is filled with zeroes. ^A zeroblob uses a fixed amount of memory
** (just an integer to hold its size) while it is being processed. ** (just an integer to hold its size) while it is being processed.
@ -3403,6 +3437,9 @@ typedef struct sqlite3_context sqlite3_context;
** **
** ^The sqlite3_bind_* routines return [SQLITE_OK] on success or an ** ^The sqlite3_bind_* routines return [SQLITE_OK] on success or an
** [error code] if anything goes wrong. ** [error code] if anything goes wrong.
** ^[SQLITE_TOOBIG] might be returned if the size of a string or BLOB
** exceeds limits imposed by [sqlite3_limit]([SQLITE_LIMIT_LENGTH]) or
** [SQLITE_MAX_LENGTH].
** ^[SQLITE_RANGE] is returned if the parameter ** ^[SQLITE_RANGE] is returned if the parameter
** index is out of range. ^[SQLITE_NOMEM] is returned if malloc() fails. ** index is out of range. ^[SQLITE_NOMEM] is returned if malloc() fails.
** **
@ -3410,12 +3447,16 @@ typedef struct sqlite3_context sqlite3_context;
** [sqlite3_bind_parameter_name()], and [sqlite3_bind_parameter_index()]. ** [sqlite3_bind_parameter_name()], and [sqlite3_bind_parameter_index()].
*/ */
SQLITE_API int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*)); SQLITE_API int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*));
SQLITE_API int sqlite3_bind_blob64(sqlite3_stmt*, int, const void*, sqlite3_uint64,
void(*)(void*));
SQLITE_API int sqlite3_bind_double(sqlite3_stmt*, int, double); SQLITE_API int sqlite3_bind_double(sqlite3_stmt*, int, double);
SQLITE_API int sqlite3_bind_int(sqlite3_stmt*, int, int); SQLITE_API int sqlite3_bind_int(sqlite3_stmt*, int, int);
SQLITE_API int sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64); SQLITE_API int sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64);
SQLITE_API int sqlite3_bind_null(sqlite3_stmt*, int); SQLITE_API int sqlite3_bind_null(sqlite3_stmt*, int);
SQLITE_API int sqlite3_bind_text(sqlite3_stmt*, int, const char*, int n, void(*)(void*)); SQLITE_API int sqlite3_bind_text(sqlite3_stmt*,int,const char*,int,void(*)(void*));
SQLITE_API int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*)); SQLITE_API int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*));
SQLITE_API int sqlite3_bind_text64(sqlite3_stmt*, int, const char*, sqlite3_uint64,
void(*)(void*), unsigned char encoding);
SQLITE_API int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*); SQLITE_API int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*);
SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n); SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n);
@ -4164,7 +4205,7 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int6
** object results in undefined behavior. ** object results in undefined behavior.
** **
** ^These routines work just like the corresponding [column access functions] ** ^These routines work just like the corresponding [column access functions]
** except that these routines take a single [protected sqlite3_value] object ** except that these routines take a single [protected sqlite3_value] object
** pointer instead of a [sqlite3_stmt*] pointer and an integer column number. ** pointer instead of a [sqlite3_stmt*] pointer and an integer column number.
** **
** ^The sqlite3_value_text16() interface extracts a UTF-16 string ** ^The sqlite3_value_text16() interface extracts a UTF-16 string
@ -4411,6 +4452,10 @@ typedef void (*sqlite3_destructor_type)(void*);
** set the return value of the application-defined function to be ** set the return value of the application-defined function to be
** a text string which is represented as UTF-8, UTF-16 native byte order, ** a text string which is represented as UTF-8, UTF-16 native byte order,
** UTF-16 little endian, or UTF-16 big endian, respectively. ** UTF-16 little endian, or UTF-16 big endian, respectively.
** ^The sqlite3_result_text64() interface sets the return value of an
** application-defined function to be a text string in an encoding
** specified by the fifth (and last) parameter, which must be one
** of [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE].
** ^SQLite takes the text result from the application from ** ^SQLite takes the text result from the application from
** the 2nd parameter of the sqlite3_result_text* interfaces. ** the 2nd parameter of the sqlite3_result_text* interfaces.
** ^If the 3rd parameter to the sqlite3_result_text* interfaces ** ^If the 3rd parameter to the sqlite3_result_text* interfaces
@ -4454,6 +4499,7 @@ typedef void (*sqlite3_destructor_type)(void*);
** the [sqlite3_context] pointer, the results are undefined. ** the [sqlite3_context] pointer, the results are undefined.
*/ */
SQLITE_API void sqlite3_result_blob(sqlite3_context*, const void*, int, void(*)(void*)); SQLITE_API void sqlite3_result_blob(sqlite3_context*, const void*, int, void(*)(void*));
SQLITE_API void sqlite3_result_blob64(sqlite3_context*,const void*,sqlite3_uint64,void(*)(void*));
SQLITE_API void sqlite3_result_double(sqlite3_context*, double); SQLITE_API void sqlite3_result_double(sqlite3_context*, double);
SQLITE_API void sqlite3_result_error(sqlite3_context*, const char*, int); SQLITE_API void sqlite3_result_error(sqlite3_context*, const char*, int);
SQLITE_API void sqlite3_result_error16(sqlite3_context*, const void*, int); SQLITE_API void sqlite3_result_error16(sqlite3_context*, const void*, int);
@ -4464,6 +4510,8 @@ SQLITE_API void sqlite3_result_int(sqlite3_context*, int);
SQLITE_API void sqlite3_result_int64(sqlite3_context*, sqlite3_int64); SQLITE_API void sqlite3_result_int64(sqlite3_context*, sqlite3_int64);
SQLITE_API void sqlite3_result_null(sqlite3_context*); SQLITE_API void sqlite3_result_null(sqlite3_context*);
SQLITE_API void sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*)); SQLITE_API void sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*));
SQLITE_API void sqlite3_result_text64(sqlite3_context*, const char*,sqlite3_uint64,
void(*)(void*), unsigned char encoding);
SQLITE_API void sqlite3_result_text16(sqlite3_context*, const void*, int, void(*)(void*)); SQLITE_API void sqlite3_result_text16(sqlite3_context*, const void*, int, void(*)(void*));
SQLITE_API void sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*)); SQLITE_API void sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*));
SQLITE_API void sqlite3_result_text16be(sqlite3_context*, const void*, int,void(*)(void*)); SQLITE_API void sqlite3_result_text16be(sqlite3_context*, const void*, int,void(*)(void*));
@ -6160,12 +6208,13 @@ SQLITE_API int sqlite3_test_control(int op, ...);
#define SQLITE_TESTCTRL_ISKEYWORD 16 #define SQLITE_TESTCTRL_ISKEYWORD 16
#define SQLITE_TESTCTRL_SCRATCHMALLOC 17 #define SQLITE_TESTCTRL_SCRATCHMALLOC 17
#define SQLITE_TESTCTRL_LOCALTIME_FAULT 18 #define SQLITE_TESTCTRL_LOCALTIME_FAULT 18
#define SQLITE_TESTCTRL_EXPLAIN_STMT 19 #define SQLITE_TESTCTRL_EXPLAIN_STMT 19 /* NOT USED */
#define SQLITE_TESTCTRL_NEVER_CORRUPT 20 #define SQLITE_TESTCTRL_NEVER_CORRUPT 20
#define SQLITE_TESTCTRL_VDBE_COVERAGE 21 #define SQLITE_TESTCTRL_VDBE_COVERAGE 21
#define SQLITE_TESTCTRL_BYTEORDER 22 #define SQLITE_TESTCTRL_BYTEORDER 22
#define SQLITE_TESTCTRL_ISINIT 23 #define SQLITE_TESTCTRL_ISINIT 23
#define SQLITE_TESTCTRL_LAST 23 #define SQLITE_TESTCTRL_SORTER_MMAP 24
#define SQLITE_TESTCTRL_LAST 24
/* /*
** CAPI3REF: SQLite Runtime Status ** CAPI3REF: SQLite Runtime Status
@ -6356,12 +6405,12 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
** the current value is always zero.)^ ** the current value is always zero.)^
** **
** [[SQLITE_DBSTATUS_CACHE_USED]] ^(<dt>SQLITE_DBSTATUS_CACHE_USED</dt> ** [[SQLITE_DBSTATUS_CACHE_USED]] ^(<dt>SQLITE_DBSTATUS_CACHE_USED</dt>
** <dd>This parameter returns the approximate number of of bytes of heap ** <dd>This parameter returns the approximate number of bytes of heap
** memory used by all pager caches associated with the database connection.)^ ** memory used by all pager caches associated with the database connection.)^
** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0. ** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0.
** **
** [[SQLITE_DBSTATUS_SCHEMA_USED]] ^(<dt>SQLITE_DBSTATUS_SCHEMA_USED</dt> ** [[SQLITE_DBSTATUS_SCHEMA_USED]] ^(<dt>SQLITE_DBSTATUS_SCHEMA_USED</dt>
** <dd>This parameter returns the approximate number of of bytes of heap ** <dd>This parameter returns the approximate number of bytes of heap
** memory used to store the schema for all databases associated ** memory used to store the schema for all databases associated
** with the connection - main, temp, and any [ATTACH]-ed databases.)^ ** with the connection - main, temp, and any [ATTACH]-ed databases.)^
** ^The full amount of memory used by the schemas is reported, even if the ** ^The full amount of memory used by the schemas is reported, even if the
@ -6370,7 +6419,7 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
** ^The highwater mark associated with SQLITE_DBSTATUS_SCHEMA_USED is always 0. ** ^The highwater mark associated with SQLITE_DBSTATUS_SCHEMA_USED is always 0.
** **
** [[SQLITE_DBSTATUS_STMT_USED]] ^(<dt>SQLITE_DBSTATUS_STMT_USED</dt> ** [[SQLITE_DBSTATUS_STMT_USED]] ^(<dt>SQLITE_DBSTATUS_STMT_USED</dt>
** <dd>This parameter returns the approximate number of of bytes of heap ** <dd>This parameter returns the approximate number of bytes of heap
** and lookaside memory used by all prepared statements associated with ** and lookaside memory used by all prepared statements associated with
** the database connection.)^ ** the database connection.)^
** ^The highwater mark associated with SQLITE_DBSTATUS_STMT_USED is always 0. ** ^The highwater mark associated with SQLITE_DBSTATUS_STMT_USED is always 0.

View File

@ -70,6 +70,8 @@ public class MessagesController implements NotificationCenter.NotificationCenter
private ArrayList<Integer> loadingFullUsers = new ArrayList<Integer>(); private ArrayList<Integer> loadingFullUsers = new ArrayList<Integer>();
private ArrayList<Integer> loadedFullUsers = new ArrayList<Integer>(); private ArrayList<Integer> loadedFullUsers = new ArrayList<Integer>();
private HashMap<Integer, ArrayList<TLRPC.TL_decryptedMessageHolder>> secretHolesQueue = new HashMap<Integer, ArrayList<TLRPC.TL_decryptedMessageHolder>>();
private boolean gettingNewDeleteTask = false; private boolean gettingNewDeleteTask = false;
private int currentDeletingTaskTime = 0; private int currentDeletingTaskTime = 0;
private ArrayList<Integer> currentDeletingTaskMids = null; private ArrayList<Integer> currentDeletingTaskMids = null;
@ -322,6 +324,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter
sendingTypings.clear(); sendingTypings.clear();
loadingFullUsers.clear(); loadingFullUsers.clear();
loadedFullUsers.clear(); loadedFullUsers.clear();
secretHolesQueue.clear();
updatesStartWaitTime = 0; updatesStartWaitTime = 0;
currentDeletingTaskTime = 0; currentDeletingTaskTime = 0;
@ -3170,15 +3173,17 @@ public class MessagesController implements NotificationCenter.NotificationCenter
} }
} else { } else {
final TLRPC.EncryptedChat exist = existingChat; final TLRPC.EncryptedChat exist = existingChat;
if (exist != null) {
newChat.user_id = exist.user_id;
newChat.auth_key = exist.auth_key;
newChat.ttl = exist.ttl;
newChat.seq_in = exist.seq_in;
newChat.seq_out = exist.seq_out;
}
AndroidUtilities.RunOnUIThread(new Runnable() { AndroidUtilities.RunOnUIThread(new Runnable() {
@Override @Override
public void run() { public void run() {
if (exist != null) { if (exist != null) {
newChat.user_id = exist.user_id;
newChat.auth_key = exist.auth_key;
newChat.ttl = exist.ttl;
newChat.seq_in = exist.seq_in;
newChat.seq_out = exist.seq_out;
putEncryptedChat(newChat, false); putEncryptedChat(newChat, false);
} }
MessagesStorage.getInstance().updateEncryptedChat(newChat); MessagesStorage.getInstance().updateEncryptedChat(newChat);
@ -3556,6 +3561,307 @@ public class MessagesController implements NotificationCenter.NotificationCenter
} }
} }
public TLRPC.Message processDecryptedObject(final TLRPC.EncryptedChat chat, final TLRPC.EncryptedFile file, int date, long random_id, TLObject object) {
if (object != null) {
int from_id = chat.admin_id;
if (from_id == UserConfig.getClientUserId()) {
from_id = chat.participant_id;
}
if (object instanceof TLRPC.TL_decryptedMessage) {
TLRPC.TL_decryptedMessage decryptedMessage = (TLRPC.TL_decryptedMessage)object;
TLRPC.TL_message newMessage = null;
if (AndroidUtilities.getPeerLayerVersion(chat.layer) >= 17) {
newMessage = new TLRPC.TL_message_secret();
newMessage.ttl = decryptedMessage.ttl;
} else {
newMessage = new TLRPC.TL_message();
newMessage.ttl = chat.ttl;
}
newMessage.message = decryptedMessage.message;
newMessage.date = date;
newMessage.local_id = newMessage.id = UserConfig.getNewMessageId();
UserConfig.saveConfig(false);
newMessage.from_id = from_id;
newMessage.to_id = new TLRPC.TL_peerUser();
newMessage.random_id = random_id;
newMessage.to_id.user_id = UserConfig.getClientUserId();
newMessage.flags = TLRPC.MESSAGE_FLAG_UNREAD;
newMessage.dialog_id = ((long)chat.id) << 32;
if (decryptedMessage.media instanceof TLRPC.TL_decryptedMessageMediaEmpty) {
newMessage.media = new TLRPC.TL_messageMediaEmpty();
} else if (decryptedMessage.media instanceof TLRPC.TL_decryptedMessageMediaContact) {
newMessage.media = new TLRPC.TL_messageMediaContact();
newMessage.media.last_name = decryptedMessage.media.last_name;
newMessage.media.first_name = decryptedMessage.media.first_name;
newMessage.media.phone_number = decryptedMessage.media.phone_number;
newMessage.media.user_id = decryptedMessage.media.user_id;
} else if (decryptedMessage.media instanceof TLRPC.TL_decryptedMessageMediaGeoPoint) {
newMessage.media = new TLRPC.TL_messageMediaGeo();
newMessage.media.geo = new TLRPC.TL_geoPoint();
newMessage.media.geo.lat = decryptedMessage.media.lat;
newMessage.media.geo._long = decryptedMessage.media._long;
} else if (decryptedMessage.media instanceof TLRPC.TL_decryptedMessageMediaPhoto) {
if (decryptedMessage.media.key == null || decryptedMessage.media.key.length != 32 || decryptedMessage.media.iv == null || decryptedMessage.media.iv.length != 32) {
return null;
}
newMessage.media = new TLRPC.TL_messageMediaPhoto();
newMessage.media.photo = new TLRPC.TL_photo();
newMessage.media.photo.user_id = newMessage.from_id;
newMessage.media.photo.date = newMessage.date;
newMessage.media.photo.caption = "";
newMessage.media.photo.geo = new TLRPC.TL_geoPointEmpty();
if (decryptedMessage.media.thumb.length != 0 && decryptedMessage.media.thumb.length <= 6000 && decryptedMessage.media.thumb_w <= 100 && decryptedMessage.media.thumb_h <= 100) {
TLRPC.TL_photoCachedSize small = new TLRPC.TL_photoCachedSize();
small.w = decryptedMessage.media.thumb_w;
small.h = decryptedMessage.media.thumb_h;
small.bytes = decryptedMessage.media.thumb;
small.type = "s";
small.location = new TLRPC.TL_fileLocationUnavailable();
newMessage.media.photo.sizes.add(small);
}
TLRPC.TL_photoSize big = new TLRPC.TL_photoSize();
big.w = decryptedMessage.media.w;
big.h = decryptedMessage.media.h;
big.type = "x";
big.size = file.size;
big.location = new TLRPC.TL_fileEncryptedLocation();
big.location.key = decryptedMessage.media.key;
big.location.iv = decryptedMessage.media.iv;
big.location.dc_id = file.dc_id;
big.location.volume_id = file.id;
big.location.secret = file.access_hash;
big.location.local_id = file.key_fingerprint;
newMessage.media.photo.sizes.add(big);
} else if (decryptedMessage.media instanceof TLRPC.TL_decryptedMessageMediaVideo) {
if (decryptedMessage.media.key == null || decryptedMessage.media.key.length != 32 || decryptedMessage.media.iv == null || decryptedMessage.media.iv.length != 32) {
return null;
}
newMessage.media = new TLRPC.TL_messageMediaVideo();
newMessage.media.video = new TLRPC.TL_videoEncrypted();
if (decryptedMessage.media.thumb.length != 0 && decryptedMessage.media.thumb.length <= 6000 && decryptedMessage.media.thumb_w <= 100 && decryptedMessage.media.thumb_h <= 100) {
newMessage.media.video.thumb = new TLRPC.TL_photoCachedSize();
newMessage.media.video.thumb.bytes = decryptedMessage.media.thumb;
newMessage.media.video.thumb.w = decryptedMessage.media.thumb_w;
newMessage.media.video.thumb.h = decryptedMessage.media.thumb_h;
newMessage.media.video.thumb.type = "s";
newMessage.media.video.thumb.location = new TLRPC.TL_fileLocationUnavailable();
} else {
newMessage.media.video.thumb = new TLRPC.TL_photoSizeEmpty();
newMessage.media.video.thumb.type = "s";
}
newMessage.media.video.duration = decryptedMessage.media.duration;
newMessage.media.video.dc_id = file.dc_id;
newMessage.media.video.w = decryptedMessage.media.w;
newMessage.media.video.h = decryptedMessage.media.h;
newMessage.media.video.date = date;
newMessage.media.video.caption = "";
newMessage.media.video.user_id = from_id;
newMessage.media.video.size = file.size;
newMessage.media.video.id = file.id;
newMessage.media.video.access_hash = file.access_hash;
newMessage.media.video.key = decryptedMessage.media.key;
newMessage.media.video.iv = decryptedMessage.media.iv;
newMessage.media.video.mime_type = decryptedMessage.media.mime_type;
if (newMessage.ttl != 0) {
newMessage.ttl = Math.max(newMessage.media.video.duration + 1, newMessage.ttl);
}
if (newMessage.media.video.mime_type == null) {
newMessage.media.video.mime_type = "video/mp4";
}
} else if (decryptedMessage.media instanceof TLRPC.TL_decryptedMessageMediaDocument) {
if (decryptedMessage.media.key == null || decryptedMessage.media.key.length != 32 || decryptedMessage.media.iv == null || decryptedMessage.media.iv.length != 32) {
return null;
}
newMessage.media = new TLRPC.TL_messageMediaDocument();
newMessage.media.document = new TLRPC.TL_documentEncrypted();
newMessage.media.document.id = file.id;
newMessage.media.document.access_hash = file.access_hash;
newMessage.media.document.user_id = decryptedMessage.media.user_id;
newMessage.media.document.date = date;
newMessage.media.document.file_name = decryptedMessage.media.file_name;
newMessage.media.document.mime_type = decryptedMessage.media.mime_type;
newMessage.media.document.size = file.size;
newMessage.media.document.key = decryptedMessage.media.key;
newMessage.media.document.iv = decryptedMessage.media.iv;
if (decryptedMessage.media.thumb.length != 0 && decryptedMessage.media.thumb.length <= 6000 && decryptedMessage.media.thumb_w <= 100 && decryptedMessage.media.thumb_h <= 100) {
newMessage.media.document.thumb = new TLRPC.TL_photoCachedSize();
newMessage.media.document.thumb.bytes = decryptedMessage.media.thumb;
newMessage.media.document.thumb.w = decryptedMessage.media.thumb_w;
newMessage.media.document.thumb.h = decryptedMessage.media.thumb_h;
newMessage.media.document.thumb.type = "s";
newMessage.media.document.thumb.location = new TLRPC.TL_fileLocationUnavailable();
} else {
newMessage.media.document.thumb = new TLRPC.TL_photoSizeEmpty();
newMessage.media.document.thumb.type = "s";
}
newMessage.media.document.dc_id = file.dc_id;
} else if (decryptedMessage.media instanceof TLRPC.TL_decryptedMessageMediaAudio) {
if (decryptedMessage.media.key == null || decryptedMessage.media.key.length != 32 || decryptedMessage.media.iv == null || decryptedMessage.media.iv.length != 32) {
return null;
}
newMessage.media = new TLRPC.TL_messageMediaAudio();
newMessage.media.audio = new TLRPC.TL_audioEncrypted();
newMessage.media.audio.id = file.id;
newMessage.media.audio.access_hash = file.access_hash;
newMessage.media.audio.user_id = from_id;
newMessage.media.audio.date = date;
newMessage.media.audio.size = file.size;
newMessage.media.audio.key = decryptedMessage.media.key;
newMessage.media.audio.iv = decryptedMessage.media.iv;
newMessage.media.audio.dc_id = file.dc_id;
newMessage.media.audio.duration = decryptedMessage.media.duration;
newMessage.media.audio.mime_type = decryptedMessage.media.mime_type;
if (newMessage.ttl != 0) {
newMessage.ttl = Math.max(newMessage.media.audio.duration + 1, newMessage.ttl);
}
if (newMessage.media.audio.mime_type == null) {
newMessage.media.audio.mime_type = "audio/ogg";
}
} else {
return null;
}
return newMessage;
} else if (object instanceof TLRPC.TL_decryptedMessageService) {
final TLRPC.TL_decryptedMessageService serviceMessage = (TLRPC.TL_decryptedMessageService)object;
if (serviceMessage.action instanceof TLRPC.TL_decryptedMessageActionSetMessageTTL || serviceMessage.action instanceof TLRPC.TL_decryptedMessageActionScreenshotMessages) {
TLRPC.TL_messageService newMessage = new TLRPC.TL_messageService();
if (serviceMessage.action instanceof TLRPC.TL_decryptedMessageActionSetMessageTTL) {
newMessage.action = new TLRPC.TL_messageEncryptedAction();
if (serviceMessage.action.ttl_seconds < 0 || serviceMessage.action.ttl_seconds > 60 * 60 * 24 * 365) {
serviceMessage.action.ttl_seconds = 60 * 60 * 24 * 365;
}
chat.ttl = serviceMessage.action.ttl_seconds;
newMessage.action.encryptedAction = serviceMessage.action;
MessagesStorage.getInstance().updateEncryptedChatTTL(chat);
} else if (serviceMessage.action instanceof TLRPC.TL_decryptedMessageActionScreenshotMessages) {
newMessage.action = new TLRPC.TL_messageEncryptedAction();
newMessage.action.encryptedAction = serviceMessage.action;
}
newMessage.local_id = newMessage.id = UserConfig.getNewMessageId();
UserConfig.saveConfig(false);
newMessage.flags = TLRPC.MESSAGE_FLAG_UNREAD;
newMessage.date = date;
newMessage.from_id = from_id;
newMessage.to_id = new TLRPC.TL_peerUser();
newMessage.to_id.user_id = UserConfig.getClientUserId();
newMessage.dialog_id = ((long)chat.id) << 32;
return newMessage;
} else if (serviceMessage.action instanceof TLRPC.TL_decryptedMessageActionFlushHistory) {
final long did = ((long)chat.id) << 32;
AndroidUtilities.RunOnUIThread(new Runnable() {
@Override
public void run() {
TLRPC.TL_dialog dialog = dialogs_dict.get(did);
if (dialog != null) {
dialog.unread_count = 0;
dialogMessage.remove(dialog.top_message);
}
MessagesStorage.getInstance().storageQueue.postRunnable(new Runnable() {
@Override
public void run() {
AndroidUtilities.RunOnUIThread(new Runnable() {
@Override
public void run() {
NotificationsController.getInstance().processReadMessages(null, did, 0, Integer.MAX_VALUE, false);
HashMap<Long, Integer> dialogsToUpdate = new HashMap<Long, Integer>();
dialogsToUpdate.put(did, 0);
NotificationsController.getInstance().processDialogsUpdateRead(dialogsToUpdate);
}
});
}
});
MessagesStorage.getInstance().deleteDialog(did, true);
NotificationCenter.getInstance().postNotificationName(NotificationCenter.removeAllMessagesFromDialog, did);
NotificationCenter.getInstance().postNotificationName(NotificationCenter.dialogsNeedReload);
}
});
return null;
} else if (serviceMessage.action instanceof TLRPC.TL_decryptedMessageActionDeleteMessages) {
if (!serviceMessage.action.random_ids.isEmpty()) {
pendingEncMessagesToDelete.addAll(serviceMessage.action.random_ids);
}
return null;
} else if (serviceMessage.action instanceof TLRPC.TL_decryptedMessageActionReadMessages) {
if (!serviceMessage.action.random_ids.isEmpty()) {
MessagesStorage.getInstance().createTaskForSecretChat(chat.id, ConnectionsManager.getInstance().getCurrentTime(), ConnectionsManager.getInstance().getCurrentTime(), 1, serviceMessage.action.random_ids);
}
} else if (serviceMessage.action instanceof TLRPC.TL_decryptedMessageActionNotifyLayer) {
int currentPeerLayer = AndroidUtilities.getPeerLayerVersion(chat.layer);
chat.layer = 0;
chat.layer = AndroidUtilities.setPeerLayerVersion(chat.layer, serviceMessage.action.layer);
MessagesStorage.getInstance().updateEncryptedChatLayer(chat);
if (currentPeerLayer < 17) {
SendMessagesHelper.getInstance().sendNotifyLayerMessage(chat, null);
}
} else if (serviceMessage.action instanceof TLRPC.TL_decryptedMessageActionResend) {
} else {
return null;
}
} else {
FileLog.e("tmessages", "unkown message " + object);
}
} else {
FileLog.e("tmessages", "unkown TLObject");
}
return null;
}
public ArrayList<TLRPC.Message> checkSecretHoles(int enc_id) {
ArrayList<TLRPC.TL_decryptedMessageHolder> holes = secretHolesQueue.get(enc_id);
if (holes == null) {
return null;
}
TLRPC.EncryptedChat chat = getEncryptedChatDB(enc_id);
if (chat == null) {
return null;
}
Collections.sort(holes, new Comparator<TLRPC.TL_decryptedMessageHolder>() {
@Override
public int compare(TLRPC.TL_decryptedMessageHolder lhs, TLRPC.TL_decryptedMessageHolder rhs) {
if (lhs.layer.out_seq_no < rhs.layer.out_seq_no) {
return 1;
} else if (lhs.layer.out_seq_no > rhs.layer.out_seq_no) {
return -1;
}
return 0;
}
});
final ArrayList<TLRPC.Message> messagesArr = new ArrayList<TLRPC.Message>();
boolean update = false;
for (int a = 0; a < holes.size(); a++) {
TLRPC.TL_decryptedMessageHolder holder = holes.get(a);
if (holder.layer.out_seq_no == chat.seq_in || chat.seq_in != holder.layer.out_seq_no - 2) {
chat.seq_in = holder.layer.out_seq_no;
holes.remove(a);
a--;
update = true;
TLRPC.Message message = processDecryptedObject(chat, holder.file, holder.date, holder.random_id, holder.layer.message);
if (message != null) {
messagesArr.add(message);
}
} else {
break;
}
}
if (!messagesArr.isEmpty()) {
MessagesStorage.getInstance().putMessages(messagesArr, true, true, false, MediaController.getInstance().getAutodownloadMask());
}
if (holes.isEmpty()) {
secretHolesQueue.remove(enc_id);
}
if (update) {
MessagesStorage.getInstance().updateEncryptedChatSeq(chat);
return messagesArr;
}
return null;
}
public TLRPC.Message decryptMessage(TLRPC.EncryptedMessage message) { public TLRPC.Message decryptMessage(TLRPC.EncryptedMessage message) {
final TLRPC.EncryptedChat chat = getEncryptedChatDB(message.chat_id); final TLRPC.EncryptedChat chat = getEncryptedChatDB(message.chat_id);
if (chat == null || chat instanceof TLRPC.TL_encryptedChatDiscarded) { if (chat == null || chat instanceof TLRPC.TL_encryptedChatDiscarded) {
@ -3574,292 +3880,55 @@ public class MessagesController implements NotificationCenter.NotificationCenter
int len = is.readInt32(); int len = is.readInt32();
TLObject object = TLClassStore.Instance().TLdeserialize(is, is.readInt32()); TLObject object = TLClassStore.Instance().TLdeserialize(is, is.readInt32());
BuffersStorage.getInstance().reuseFreeBuffer(is); BuffersStorage.getInstance().reuseFreeBuffer(is);
if (object != null) { if (object instanceof TLRPC.TL_decryptedMessageLayer) {
int from_id = chat.admin_id; final TLRPC.TL_decryptedMessageLayer layer = (TLRPC.TL_decryptedMessageLayer)object;
if (from_id == UserConfig.getClientUserId()) { if (chat.seq_in == 0 && chat.seq_out == 0) {
from_id = chat.participant_id; if (chat.admin_id == UserConfig.getClientUserId()) {
} chat.seq_out = 1;
} else {
if (object instanceof TLRPC.TL_decryptedMessageLayer) { chat.seq_in = 1;
final TLRPC.TL_decryptedMessageLayer layer = (TLRPC.TL_decryptedMessageLayer)object;
if (chat.seq_in == 0 && chat.seq_out == 0) {
if (chat.admin_id == UserConfig.getClientUserId()) {
chat.seq_out = 1;
} else {
chat.seq_in = 1;
}
} }
if (chat.seq_in != layer.out_seq_no && chat.seq_in != layer.out_seq_no - 2) { }
if (layer.out_seq_no < chat.seq_in) {
return null;
}
if (chat.seq_in != layer.out_seq_no && chat.seq_in != layer.out_seq_no - 2) {
/*TLRPC.Message decryptedMessage = processDecryptedObject(chat, message, layer.message);
if (decryptedMessage == null) {
final TLRPC.TL_encryptedChatDiscarded newChat = new TLRPC.TL_encryptedChatDiscarded();
newChat.id = chat.id;
newChat.user_id = chat.user_id;
newChat.auth_key = chat.auth_key;
newChat.seq_in = chat.seq_in;
newChat.seq_out = chat.seq_out;
AndroidUtilities.RunOnUIThread(new Runnable() { AndroidUtilities.RunOnUIThread(new Runnable() {
@Override @Override
public void run() { public void run() {
final TLRPC.TL_encryptedChatDiscarded newChat = new TLRPC.TL_encryptedChatDiscarded(); putEncryptedChat(newChat, false);
newChat.id = chat.id;
newChat.user_id = chat.user_id;
newChat.auth_key = chat.auth_key;
newChat.seq_in = chat.seq_in;
newChat.seq_out = chat.seq_out;
MessagesStorage.getInstance().updateEncryptedChat(newChat); MessagesStorage.getInstance().updateEncryptedChat(newChat);
AndroidUtilities.RunOnUIThread(new Runnable() { NotificationCenter.getInstance().postNotificationName(NotificationCenter.encryptedChatUpdated, newChat);
@Override
public void run() {
putEncryptedChat(newChat, false);
NotificationCenter.getInstance().postNotificationName(NotificationCenter.encryptedChatUpdated, newChat);
}
});
declineSecretChat(chat.id);
} }
}); });
return null; declineSecretChat(chat.id);
}*/
ArrayList<TLRPC.TL_decryptedMessageHolder> arr = secretHolesQueue.get(chat.id);
if (arr == null) {
arr = new ArrayList<TLRPC.TL_decryptedMessageHolder>();
secretHolesQueue.put(chat.id, arr);
} }
chat.seq_in = layer.out_seq_no; TLRPC.TL_decryptedMessageHolder holder = new TLRPC.TL_decryptedMessageHolder();
MessagesStorage.getInstance().updateEncryptedChatSeq(chat); holder.layer = layer;
object = layer.message; holder.file = message.file;
holder.random_id = message.random_id;
holder.date = message.date;
arr.add(holder);
return null;
} }
chat.seq_in = layer.out_seq_no;
if (object instanceof TLRPC.TL_decryptedMessage) { MessagesStorage.getInstance().updateEncryptedChatSeq(chat);
TLRPC.TL_decryptedMessage decryptedMessage = (TLRPC.TL_decryptedMessage)object; object = layer.message;
TLRPC.TL_message newMessage = null;
if (AndroidUtilities.getPeerLayerVersion(chat.layer) >= 17) {
newMessage = new TLRPC.TL_message_secret();
newMessage.ttl = decryptedMessage.ttl;
} else {
newMessage = new TLRPC.TL_message();
newMessage.ttl = chat.ttl;
}
newMessage.message = decryptedMessage.message;
newMessage.date = message.date;
newMessage.local_id = newMessage.id = UserConfig.getNewMessageId();
UserConfig.saveConfig(false);
newMessage.from_id = from_id;
newMessage.to_id = new TLRPC.TL_peerUser();
newMessage.random_id = message.random_id;
newMessage.to_id.user_id = UserConfig.getClientUserId();
newMessage.flags = TLRPC.MESSAGE_FLAG_UNREAD;
newMessage.dialog_id = ((long)chat.id) << 32;
if (decryptedMessage.media instanceof TLRPC.TL_decryptedMessageMediaEmpty) {
newMessage.media = new TLRPC.TL_messageMediaEmpty();
} else if (decryptedMessage.media instanceof TLRPC.TL_decryptedMessageMediaContact) {
newMessage.media = new TLRPC.TL_messageMediaContact();
newMessage.media.last_name = decryptedMessage.media.last_name;
newMessage.media.first_name = decryptedMessage.media.first_name;
newMessage.media.phone_number = decryptedMessage.media.phone_number;
newMessage.media.user_id = decryptedMessage.media.user_id;
} else if (decryptedMessage.media instanceof TLRPC.TL_decryptedMessageMediaGeoPoint) {
newMessage.media = new TLRPC.TL_messageMediaGeo();
newMessage.media.geo = new TLRPC.TL_geoPoint();
newMessage.media.geo.lat = decryptedMessage.media.lat;
newMessage.media.geo._long = decryptedMessage.media._long;
} else if (decryptedMessage.media instanceof TLRPC.TL_decryptedMessageMediaPhoto) {
if (decryptedMessage.media.key == null || decryptedMessage.media.key.length != 32 || decryptedMessage.media.iv == null || decryptedMessage.media.iv.length != 32) {
return null;
}
newMessage.media = new TLRPC.TL_messageMediaPhoto();
newMessage.media.photo = new TLRPC.TL_photo();
newMessage.media.photo.user_id = newMessage.from_id;
newMessage.media.photo.date = newMessage.date;
newMessage.media.photo.caption = "";
newMessage.media.photo.geo = new TLRPC.TL_geoPointEmpty();
if (decryptedMessage.media.thumb.length != 0 && decryptedMessage.media.thumb.length <= 6000 && decryptedMessage.media.thumb_w <= 100 && decryptedMessage.media.thumb_h <= 100) {
TLRPC.TL_photoCachedSize small = new TLRPC.TL_photoCachedSize();
small.w = decryptedMessage.media.thumb_w;
small.h = decryptedMessage.media.thumb_h;
small.bytes = decryptedMessage.media.thumb;
small.type = "s";
small.location = new TLRPC.TL_fileLocationUnavailable();
newMessage.media.photo.sizes.add(small);
}
TLRPC.TL_photoSize big = new TLRPC.TL_photoSize();
big.w = decryptedMessage.media.w;
big.h = decryptedMessage.media.h;
big.type = "x";
big.size = message.file.size;
big.location = new TLRPC.TL_fileEncryptedLocation();
big.location.key = decryptedMessage.media.key;
big.location.iv = decryptedMessage.media.iv;
big.location.dc_id = message.file.dc_id;
big.location.volume_id = message.file.id;
big.location.secret = message.file.access_hash;
big.location.local_id = message.file.key_fingerprint;
newMessage.media.photo.sizes.add(big);
} else if (decryptedMessage.media instanceof TLRPC.TL_decryptedMessageMediaVideo) {
if (decryptedMessage.media.key == null || decryptedMessage.media.key.length != 32 || decryptedMessage.media.iv == null || decryptedMessage.media.iv.length != 32) {
return null;
}
newMessage.media = new TLRPC.TL_messageMediaVideo();
newMessage.media.video = new TLRPC.TL_videoEncrypted();
if (decryptedMessage.media.thumb.length != 0 && decryptedMessage.media.thumb.length <= 6000 && decryptedMessage.media.thumb_w <= 100 && decryptedMessage.media.thumb_h <= 100) {
newMessage.media.video.thumb = new TLRPC.TL_photoCachedSize();
newMessage.media.video.thumb.bytes = decryptedMessage.media.thumb;
newMessage.media.video.thumb.w = decryptedMessage.media.thumb_w;
newMessage.media.video.thumb.h = decryptedMessage.media.thumb_h;
newMessage.media.video.thumb.type = "s";
newMessage.media.video.thumb.location = new TLRPC.TL_fileLocationUnavailable();
} else {
newMessage.media.video.thumb = new TLRPC.TL_photoSizeEmpty();
newMessage.media.video.thumb.type = "s";
}
newMessage.media.video.duration = decryptedMessage.media.duration;
newMessage.media.video.dc_id = message.file.dc_id;
newMessage.media.video.w = decryptedMessage.media.w;
newMessage.media.video.h = decryptedMessage.media.h;
newMessage.media.video.date = message.date;
newMessage.media.video.caption = "";
newMessage.media.video.user_id = from_id;
newMessage.media.video.size = message.file.size;
newMessage.media.video.id = message.file.id;
newMessage.media.video.access_hash = message.file.access_hash;
newMessage.media.video.key = decryptedMessage.media.key;
newMessage.media.video.iv = decryptedMessage.media.iv;
newMessage.media.video.mime_type = decryptedMessage.media.mime_type;
if (newMessage.ttl != 0) {
newMessage.ttl = Math.max(newMessage.media.video.duration + 1, newMessage.ttl);
}
if (newMessage.media.video.mime_type == null) {
newMessage.media.video.mime_type = "video/mp4";
}
} else if (decryptedMessage.media instanceof TLRPC.TL_decryptedMessageMediaDocument) {
if (decryptedMessage.media.key == null || decryptedMessage.media.key.length != 32 || decryptedMessage.media.iv == null || decryptedMessage.media.iv.length != 32) {
return null;
}
newMessage.media = new TLRPC.TL_messageMediaDocument();
newMessage.media.document = new TLRPC.TL_documentEncrypted();
newMessage.media.document.id = message.file.id;
newMessage.media.document.access_hash = message.file.access_hash;
newMessage.media.document.user_id = decryptedMessage.media.user_id;
newMessage.media.document.date = message.date;
newMessage.media.document.file_name = decryptedMessage.media.file_name;
newMessage.media.document.mime_type = decryptedMessage.media.mime_type;
newMessage.media.document.size = message.file.size;
newMessage.media.document.key = decryptedMessage.media.key;
newMessage.media.document.iv = decryptedMessage.media.iv;
if (decryptedMessage.media.thumb.length != 0 && decryptedMessage.media.thumb.length <= 6000 && decryptedMessage.media.thumb_w <= 100 && decryptedMessage.media.thumb_h <= 100) {
newMessage.media.document.thumb = new TLRPC.TL_photoCachedSize();
newMessage.media.document.thumb.bytes = decryptedMessage.media.thumb;
newMessage.media.document.thumb.w = decryptedMessage.media.thumb_w;
newMessage.media.document.thumb.h = decryptedMessage.media.thumb_h;
newMessage.media.document.thumb.type = "s";
newMessage.media.document.thumb.location = new TLRPC.TL_fileLocationUnavailable();
} else {
newMessage.media.document.thumb = new TLRPC.TL_photoSizeEmpty();
newMessage.media.document.thumb.type = "s";
}
newMessage.media.document.dc_id = message.file.dc_id;
} else if (decryptedMessage.media instanceof TLRPC.TL_decryptedMessageMediaAudio) {
if (decryptedMessage.media.key == null || decryptedMessage.media.key.length != 32 || decryptedMessage.media.iv == null || decryptedMessage.media.iv.length != 32) {
return null;
}
newMessage.media = new TLRPC.TL_messageMediaAudio();
newMessage.media.audio = new TLRPC.TL_audioEncrypted();
newMessage.media.audio.id = message.file.id;
newMessage.media.audio.access_hash = message.file.access_hash;
newMessage.media.audio.user_id = from_id;
newMessage.media.audio.date = message.date;
newMessage.media.audio.size = message.file.size;
newMessage.media.audio.key = decryptedMessage.media.key;
newMessage.media.audio.iv = decryptedMessage.media.iv;
newMessage.media.audio.dc_id = message.file.dc_id;
newMessage.media.audio.duration = decryptedMessage.media.duration;
newMessage.media.audio.mime_type = decryptedMessage.media.mime_type;
if (newMessage.ttl != 0) {
newMessage.ttl = Math.max(newMessage.media.audio.duration + 1, newMessage.ttl);
}
if (newMessage.media.audio.mime_type == null) {
newMessage.media.audio.mime_type = "audio/ogg";
}
} else {
return null;
}
return newMessage;
} else if (object instanceof TLRPC.TL_decryptedMessageService) {
final TLRPC.TL_decryptedMessageService serviceMessage = (TLRPC.TL_decryptedMessageService)object;
if (serviceMessage.action instanceof TLRPC.TL_decryptedMessageActionSetMessageTTL || serviceMessage.action instanceof TLRPC.TL_decryptedMessageActionScreenshotMessages) {
TLRPC.TL_messageService newMessage = new TLRPC.TL_messageService();
if (serviceMessage.action instanceof TLRPC.TL_decryptedMessageActionSetMessageTTL) {
newMessage.action = new TLRPC.TL_messageEncryptedAction();
if (serviceMessage.action.ttl_seconds < 0 || serviceMessage.action.ttl_seconds > 60 * 60 * 24 * 365) {
serviceMessage.action.ttl_seconds = 60 * 60 * 24 * 365;
}
chat.ttl = serviceMessage.action.ttl_seconds;
newMessage.action.encryptedAction = serviceMessage.action;
MessagesStorage.getInstance().updateEncryptedChatTTL(chat);
} else if (serviceMessage.action instanceof TLRPC.TL_decryptedMessageActionScreenshotMessages) {
newMessage.action = new TLRPC.TL_messageEncryptedAction();
newMessage.action.encryptedAction = serviceMessage.action;
}
newMessage.local_id = newMessage.id = UserConfig.getNewMessageId();
UserConfig.saveConfig(false);
newMessage.flags = TLRPC.MESSAGE_FLAG_UNREAD;
newMessage.date = message.date;
newMessage.from_id = from_id;
newMessage.to_id = new TLRPC.TL_peerUser();
newMessage.to_id.user_id = UserConfig.getClientUserId();
newMessage.dialog_id = ((long)chat.id) << 32;
return newMessage;
} else if (serviceMessage.action instanceof TLRPC.TL_decryptedMessageActionFlushHistory) {
final long did = ((long)chat.id) << 32;
AndroidUtilities.RunOnUIThread(new Runnable() {
@Override
public void run() {
TLRPC.TL_dialog dialog = dialogs_dict.get(did);
if (dialog != null) {
dialog.unread_count = 0;
dialogMessage.remove(dialog.top_message);
}
MessagesStorage.getInstance().storageQueue.postRunnable(new Runnable() {
@Override
public void run() {
AndroidUtilities.RunOnUIThread(new Runnable() {
@Override
public void run() {
NotificationsController.getInstance().processReadMessages(null, did, 0, Integer.MAX_VALUE, false);
HashMap<Long, Integer> dialogsToUpdate = new HashMap<Long, Integer>();
dialogsToUpdate.put(did, 0);
NotificationsController.getInstance().processDialogsUpdateRead(dialogsToUpdate);
}
});
}
});
MessagesStorage.getInstance().deleteDialog(did, true);
NotificationCenter.getInstance().postNotificationName(NotificationCenter.removeAllMessagesFromDialog, did);
NotificationCenter.getInstance().postNotificationName(NotificationCenter.dialogsNeedReload);
}
});
return null;
} else if (serviceMessage.action instanceof TLRPC.TL_decryptedMessageActionDeleteMessages) {
if (!serviceMessage.action.random_ids.isEmpty()) {
pendingEncMessagesToDelete.addAll(serviceMessage.action.random_ids);
}
return null;
} else if (serviceMessage.action instanceof TLRPC.TL_decryptedMessageActionReadMessages) {
if (!serviceMessage.action.random_ids.isEmpty()) {
MessagesStorage.getInstance().createTaskForSecretChat(chat.id, ConnectionsManager.getInstance().getCurrentTime(), ConnectionsManager.getInstance().getCurrentTime(), 1, serviceMessage.action.random_ids);
}
} else if (serviceMessage.action instanceof TLRPC.TL_decryptedMessageActionNotifyLayer) {
AndroidUtilities.RunOnUIThread(new Runnable() {
@Override
public void run() {
int currentPeerLayer = AndroidUtilities.getPeerLayerVersion(chat.layer);
chat.layer = 0;
chat.layer = AndroidUtilities.setPeerLayerVersion(chat.layer, serviceMessage.action.layer);
MessagesStorage.getInstance().updateEncryptedChatLayer(chat);
if (currentPeerLayer < 17) {
SendMessagesHelper.getInstance().sendNotifyLayerMessage(chat, null);
}
}
});
} else if (serviceMessage.action instanceof TLRPC.TL_decryptedMessageActionResend) {
} else {
return null;
}
} else {
FileLog.e("tmessages", "unkown message " + object);
}
} else {
FileLog.e("tmessages", "unkown TLObject");
} }
return processDecryptedObject(chat, message.file, message.date, message.random_id, object);
} else { } else {
BuffersStorage.getInstance().reuseFreeBuffer(is); BuffersStorage.getInstance().reuseFreeBuffer(is);
FileLog.e("tmessages", "fingerprint mismatch"); FileLog.e("tmessages", "fingerprint mismatch");

View File

@ -110,6 +110,7 @@ public class MessagesStorage {
database.executeFast("CREATE TABLE download_queue(uid INTEGER, type INTEGER, date INTEGER, data BLOB, PRIMARY KEY (uid, type));").stepThis().dispose(); database.executeFast("CREATE TABLE download_queue(uid INTEGER, type INTEGER, date INTEGER, data BLOB, PRIMARY KEY (uid, type));").stepThis().dispose();
database.executeFast("CREATE TABLE dialog_settings(did INTEGER PRIMARY KEY, flags INTEGER);").stepThis().dispose(); database.executeFast("CREATE TABLE dialog_settings(did INTEGER PRIMARY KEY, flags INTEGER);").stepThis().dispose();
database.executeFast("CREATE TABLE messages_seq(mid INTEGER PRIMARY KEY, seq_in INTEGER, seq_out INTEGER);").stepThis().dispose(); database.executeFast("CREATE TABLE messages_seq(mid INTEGER PRIMARY KEY, seq_in INTEGER, seq_out INTEGER);").stepThis().dispose();
database.executeFast("CREATE TABLE secret_holes(uid INTEGER, seq_in INTEGER, seq_out INTEGER, data BLOB, PRIMARY KEY (uid, seq_in, seq_out));").stepThis().dispose();
//database.executeFast("CREATE TABLE attach_data(uid INTEGER, id INTEGER, data BLOB, PRIMARY KEY (uid, id))").stepThis().dispose(); //database.executeFast("CREATE TABLE attach_data(uid INTEGER, id INTEGER, data BLOB, PRIMARY KEY (uid, id))").stepThis().dispose();
@ -141,7 +142,7 @@ public class MessagesStorage {
database.executeFast("CREATE INDEX IF NOT EXISTS seq_idx_messages_seq ON messages_seq(seq_in, seq_out);").stepThis().dispose(); database.executeFast("CREATE INDEX IF NOT EXISTS seq_idx_messages_seq ON messages_seq(seq_in, seq_out);").stepThis().dispose();
database.executeFast("PRAGMA user_version = 7").stepThis().dispose(); database.executeFast("PRAGMA user_version = 8").stepThis().dispose();
} else { } else {
try { try {
SQLiteCursor cursor = database.queryFinalized("SELECT seq, pts, date, qts, lsv, sg, pbytes FROM params WHERE id = 1"); SQLiteCursor cursor = database.queryFinalized("SELECT seq, pts, date, qts, lsv, sg, pbytes FROM params WHERE id = 1");
@ -173,7 +174,7 @@ public class MessagesStorage {
} }
int version = database.executeInt("PRAGMA user_version"); int version = database.executeInt("PRAGMA user_version");
if (version < 7) { if (version < 8) {
updateDbToLastVersion(version); updateDbToLastVersion(version);
} }
} }
@ -303,6 +304,11 @@ public class MessagesStorage {
database.executeFast("PRAGMA user_version = 7").stepThis().dispose(); database.executeFast("PRAGMA user_version = 7").stepThis().dispose();
version = 7; version = 7;
} }
if (version == 7 && version < 8) {
database.executeFast("CREATE TABLE IF NOT EXISTS secret_holes(uid INTEGER, seq_in INTEGER, seq_out INTEGER, data BLOB, PRIMARY KEY (uid, seq_in, seq_out));").stepThis().dispose();
database.executeFast("PRAGMA user_version = 8").stepThis().dispose();
version = 8;
}
} catch (Exception e) { } catch (Exception e) {
FileLog.e("tmessages", e); FileLog.e("tmessages", e);
} }
@ -665,6 +671,7 @@ public class MessagesStorage {
} }
} else { } else {
database.executeFast("DELETE FROM enc_chats WHERE uid = " + high_id).stepThis().dispose(); database.executeFast("DELETE FROM enc_chats WHERE uid = " + high_id).stepThis().dispose();
database.executeFast("DELETE FROM secret_holes WHERE uid = " + high_id).stepThis().dispose();
} }
} }
database.executeFast("UPDATE dialogs SET unread_count = 0 WHERE did = " + did).stepThis().dispose(); database.executeFast("UPDATE dialogs SET unread_count = 0 WHERE did = " + did).stepThis().dispose();
@ -2798,6 +2805,60 @@ public class MessagesStorage {
}); });
} }
public void getHoleMessages() {
storageQueue.postRunnable(new Runnable() {
@Override
public void run() {
try {
} catch (Exception e) {
FileLog.e("tmessages", e);
}
}
});
}
public void clearHoleMessages(final int enc_id) {
storageQueue.postRunnable(new Runnable() {
@Override
public void run() {
try {
database.executeFast("DELETE FROM secret_holes WHERE uid = " + enc_id).stepThis().dispose();
} catch (Exception e) {
FileLog.e("tmessages", e);
}
}
});
}
public void putHoleMessage(final int enc_id, final TLRPC.Message message) {
if (message == null) {
return;
}
storageQueue.postRunnable(new Runnable() {
@Override
public void run() {
try {
SQLitePreparedStatement state = database.executeFast("REPLACE INTO secret_holes VALUES(?, ?, ?, ?)");
state.requery();
ByteBufferDesc data = buffersStorage.getFreeBuffer(message.getObjectSize());
message.serializeToStream(data);
state.bindInteger(1, enc_id);
state.bindInteger(2, message.seq_in);
state.bindInteger(3, message.seq_out);
state.bindByteBuffer(4, data.buffer);
state.step();
buffersStorage.reuseFreeBuffer(data);
state.dispose();
} catch (Exception e) {
FileLog.e("tmessages", e);
}
}
});
}
public void setMessageSeq(final int mid, final int seq_in, final int seq_out) { public void setMessageSeq(final int mid, final int seq_in, final int seq_out) {
storageQueue.postRunnable(new Runnable() { storageQueue.postRunnable(new Runnable() {
@Override @Override

View File

@ -1177,169 +1177,169 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
if (req == null || chat.auth_key == null || chat instanceof TLRPC.TL_encryptedChatRequested || chat instanceof TLRPC.TL_encryptedChatWaiting) { if (req == null || chat.auth_key == null || chat instanceof TLRPC.TL_encryptedChatRequested || chat instanceof TLRPC.TL_encryptedChatWaiting) {
return; return;
} }
TLObject toEncryptObject = null; Utilities.stageQueue.postRunnable(new Runnable() {
if (AndroidUtilities.getPeerLayerVersion(chat.layer) >= 17) {
TLRPC.TL_decryptedMessageLayer layer = new TLRPC.TL_decryptedMessageLayer();
layer.layer = CURRENT_SECRET_CHAT_LAYER;
layer.message = req;
layer.random_bytes = new byte[Math.max(1, (int) Math.ceil(Utilities.random.nextDouble() * 16))];
Utilities.random.nextBytes(layer.random_bytes);
toEncryptObject = layer;
if (chat.seq_in == 0 && chat.seq_out == 0) {
if (chat.admin_id == UserConfig.getClientUserId()) {
chat.seq_out = 1;
} else {
chat.seq_in = 1;
}
}
if (newMsgObj.seq_in == 0 && newMsgObj.seq_out == 0) {
layer.in_seq_no = chat.seq_in;
layer.out_seq_no = chat.seq_out;
chat.seq_out += 2;
MessagesStorage.getInstance().updateEncryptedChatSeq(chat);
if (newMsgObj != null) {
newMsgObj.seq_in = layer.in_seq_no;
newMsgObj.seq_out = layer.out_seq_no;
MessagesStorage.getInstance().setMessageSeq(newMsgObj.id, newMsgObj.seq_in, newMsgObj.seq_out);
}
} else {
layer.in_seq_no = newMsgObj.seq_in;
layer.out_seq_no = newMsgObj.seq_out;
}
} else {
toEncryptObject = req;
}
int len = toEncryptObject.getObjectSize();
ByteBufferDesc toEncrypt = BuffersStorage.getInstance().getFreeBuffer(4 + len);
toEncrypt.writeInt32(len);
toEncryptObject.serializeToStream(toEncrypt);
byte[] messageKeyFull = Utilities.computeSHA1(toEncrypt.buffer);
byte[] messageKey = new byte[16];
System.arraycopy(messageKeyFull, messageKeyFull.length - 16, messageKey, 0, 16);
MessageKeyData keyData = Utilities.generateMessageKeyData(chat.auth_key, messageKey, false);
len = toEncrypt.length();
int extraLen = len % 16 != 0 ? 16 - len % 16 : 0;
ByteBufferDesc dataForEncryption = BuffersStorage.getInstance().getFreeBuffer(len + extraLen);
toEncrypt.position(0);
dataForEncryption.writeRaw(toEncrypt);
if (extraLen != 0) {
byte[] b = new byte[extraLen];
Utilities.random.nextBytes(b);
dataForEncryption.writeRaw(b);
}
BuffersStorage.getInstance().reuseFreeBuffer(toEncrypt);
Utilities.aesIgeEncryption(dataForEncryption.buffer, keyData.aesKey, keyData.aesIv, true, false, 0, dataForEncryption.limit());
ByteBufferDesc data = BuffersStorage.getInstance().getFreeBuffer(8 + messageKey.length + dataForEncryption.length());
dataForEncryption.position(0);
data.writeInt64(chat.key_fingerprint);
data.writeRaw(messageKey);
data.writeRaw(dataForEncryption);
BuffersStorage.getInstance().reuseFreeBuffer(dataForEncryption);
data.position(0);
TLObject reqToSend = null;
if (encryptedFile == null) {
if (req instanceof TLRPC.TL_decryptedMessageService) {
TLRPC.TL_messages_sendEncryptedService req2 = new TLRPC.TL_messages_sendEncryptedService();
req2.data = data;
req2.random_id = req.random_id;
req2.peer = new TLRPC.TL_inputEncryptedChat();
req2.peer.chat_id = chat.id;
req2.peer.access_hash = chat.access_hash;
reqToSend = req2;
} else {
TLRPC.TL_messages_sendEncrypted req2 = new TLRPC.TL_messages_sendEncrypted();
req2.data = data;
req2.random_id = req.random_id;
req2.peer = new TLRPC.TL_inputEncryptedChat();
req2.peer.chat_id = chat.id;
req2.peer.access_hash = chat.access_hash;
reqToSend = req2;
}
} else {
TLRPC.TL_messages_sendEncryptedFile req2 = new TLRPC.TL_messages_sendEncryptedFile();
req2.data = data;
req2.random_id = req.random_id;
req2.peer = new TLRPC.TL_inputEncryptedChat();
req2.peer.chat_id = chat.id;
req2.peer.access_hash = chat.access_hash;
req2.file = encryptedFile;
reqToSend = req2;
}
ConnectionsManager.getInstance().performRpc(reqToSend, new RPCRequest.RPCRequestDelegate() {
@Override @Override
public void run(TLObject response, TLRPC.TL_error error) { public void run() {
if (error == null) { TLObject toEncryptObject = null;
if (req.action instanceof TLRPC.TL_decryptedMessageActionNotifyLayer) { if (AndroidUtilities.getPeerLayerVersion(chat.layer) >= 17) {
AndroidUtilities.RunOnUIThread(new Runnable() { TLRPC.TL_decryptedMessageLayer layer = new TLRPC.TL_decryptedMessageLayer();
@Override layer.layer = CURRENT_SECRET_CHAT_LAYER;
public void run() { layer.message = req;
layer.random_bytes = new byte[Math.max(1, (int) Math.ceil(Utilities.random.nextDouble() * 16))];
Utilities.random.nextBytes(layer.random_bytes);
toEncryptObject = layer;
if (chat.seq_in == 0 && chat.seq_out == 0) {
if (chat.admin_id == UserConfig.getClientUserId()) {
chat.seq_out = 1;
} else {
chat.seq_in = 1;
}
}
if (newMsgObj.seq_in == 0 && newMsgObj.seq_out == 0) {
layer.in_seq_no = chat.seq_in;
layer.out_seq_no = chat.seq_out;
chat.seq_out += 2;
MessagesStorage.getInstance().updateEncryptedChatSeq(chat);
if (newMsgObj != null) {
newMsgObj.seq_in = layer.in_seq_no;
newMsgObj.seq_out = layer.out_seq_no;
MessagesStorage.getInstance().setMessageSeq(newMsgObj.id, newMsgObj.seq_in, newMsgObj.seq_out);
}
} else {
layer.in_seq_no = newMsgObj.seq_in;
layer.out_seq_no = newMsgObj.seq_out;
}
} else {
toEncryptObject = req;
}
int len = toEncryptObject.getObjectSize();
ByteBufferDesc toEncrypt = BuffersStorage.getInstance().getFreeBuffer(4 + len);
toEncrypt.writeInt32(len);
toEncryptObject.serializeToStream(toEncrypt);
byte[] messageKeyFull = Utilities.computeSHA1(toEncrypt.buffer);
byte[] messageKey = new byte[16];
System.arraycopy(messageKeyFull, messageKeyFull.length - 16, messageKey, 0, 16);
MessageKeyData keyData = Utilities.generateMessageKeyData(chat.auth_key, messageKey, false);
len = toEncrypt.length();
int extraLen = len % 16 != 0 ? 16 - len % 16 : 0;
ByteBufferDesc dataForEncryption = BuffersStorage.getInstance().getFreeBuffer(len + extraLen);
toEncrypt.position(0);
dataForEncryption.writeRaw(toEncrypt);
if (extraLen != 0) {
byte[] b = new byte[extraLen];
Utilities.random.nextBytes(b);
dataForEncryption.writeRaw(b);
}
BuffersStorage.getInstance().reuseFreeBuffer(toEncrypt);
Utilities.aesIgeEncryption(dataForEncryption.buffer, keyData.aesKey, keyData.aesIv, true, false, 0, dataForEncryption.limit());
ByteBufferDesc data = BuffersStorage.getInstance().getFreeBuffer(8 + messageKey.length + dataForEncryption.length());
dataForEncryption.position(0);
data.writeInt64(chat.key_fingerprint);
data.writeRaw(messageKey);
data.writeRaw(dataForEncryption);
BuffersStorage.getInstance().reuseFreeBuffer(dataForEncryption);
data.position(0);
TLObject reqToSend = null;
if (encryptedFile == null) {
if (req instanceof TLRPC.TL_decryptedMessageService) {
TLRPC.TL_messages_sendEncryptedService req2 = new TLRPC.TL_messages_sendEncryptedService();
req2.data = data;
req2.random_id = req.random_id;
req2.peer = new TLRPC.TL_inputEncryptedChat();
req2.peer.chat_id = chat.id;
req2.peer.access_hash = chat.access_hash;
reqToSend = req2;
} else {
TLRPC.TL_messages_sendEncrypted req2 = new TLRPC.TL_messages_sendEncrypted();
req2.data = data;
req2.random_id = req.random_id;
req2.peer = new TLRPC.TL_inputEncryptedChat();
req2.peer.chat_id = chat.id;
req2.peer.access_hash = chat.access_hash;
reqToSend = req2;
}
} else {
TLRPC.TL_messages_sendEncryptedFile req2 = new TLRPC.TL_messages_sendEncryptedFile();
req2.data = data;
req2.random_id = req.random_id;
req2.peer = new TLRPC.TL_inputEncryptedChat();
req2.peer.chat_id = chat.id;
req2.peer.access_hash = chat.access_hash;
req2.file = encryptedFile;
reqToSend = req2;
}
ConnectionsManager.getInstance().performRpc(reqToSend, new RPCRequest.RPCRequestDelegate() {
@Override
public void run(TLObject response, TLRPC.TL_error error) {
if (error == null) {
if (req.action instanceof TLRPC.TL_decryptedMessageActionNotifyLayer) {
TLRPC.EncryptedChat currentChat = MessagesController.getInstance().getEncryptedChat(chat.id); TLRPC.EncryptedChat currentChat = MessagesController.getInstance().getEncryptedChat(chat.id);
sendingNotifyLayer.remove((Integer)currentChat.id); sendingNotifyLayer.remove((Integer)currentChat.id);
currentChat.layer = AndroidUtilities.setMyLayerVersion(currentChat.layer, CURRENT_SECRET_CHAT_LAYER); currentChat.layer = AndroidUtilities.setMyLayerVersion(currentChat.layer, CURRENT_SECRET_CHAT_LAYER);
MessagesStorage.getInstance().updateEncryptedChatLayer(currentChat); MessagesStorage.getInstance().updateEncryptedChatLayer(currentChat);
} }
});
}
}
if (newMsgObj != null) {
if (error == null) {
final String attachPath = newMsgObj.attachPath;
final TLRPC.messages_SentEncryptedMessage res = (TLRPC.messages_SentEncryptedMessage) response;
if (newMsgObj.action instanceof TLRPC.TL_messageEncryptedAction) {
if (newMsgObj.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionScreenshotMessages || newMsgObj.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionSetMessageTTL) {
newMsgObj.date = res.date;
}
} }
if (res.file instanceof TLRPC.TL_encryptedFile) { if (newMsgObj != null) {
processSentMessage(newMsgObj, null, res.file, req, originalPath); if (error == null) {
} final String attachPath = newMsgObj.attachPath;
MessagesStorage.getInstance().storageQueue.postRunnable(new Runnable() { final TLRPC.messages_SentEncryptedMessage res = (TLRPC.messages_SentEncryptedMessage) response;
@Override
public void run() {
if (newMsgObj.action instanceof TLRPC.TL_messageEncryptedAction) { if (newMsgObj.action instanceof TLRPC.TL_messageEncryptedAction) {
if (!(newMsgObj.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionScreenshotMessages || newMsgObj.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionSetMessageTTL)) { if (newMsgObj.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionScreenshotMessages || newMsgObj.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionSetMessageTTL) {
res.date = 0; newMsgObj.date = res.date;
} }
} }
MessagesStorage.getInstance().updateMessageStateAndId(newMsgObj.random_id, newMsgObj.id, newMsgObj.id, res.date, false); if (res.file instanceof TLRPC.TL_encryptedFile) {
processSentMessage(newMsgObj, null, res.file, req, originalPath);
}
MessagesStorage.getInstance().storageQueue.postRunnable(new Runnable() {
@Override
public void run() {
if (newMsgObj.action instanceof TLRPC.TL_messageEncryptedAction) {
if (!(newMsgObj.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionScreenshotMessages || newMsgObj.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionSetMessageTTL)) {
res.date = 0;
}
}
MessagesStorage.getInstance().updateMessageStateAndId(newMsgObj.random_id, newMsgObj.id, newMsgObj.id, res.date, false);
AndroidUtilities.RunOnUIThread(new Runnable() {
@Override
public void run() {
newMsgObj.send_state = MessageObject.MESSAGE_SEND_STATE_SENT;
NotificationCenter.getInstance().postNotificationName(NotificationCenter.messageReceivedByServer, newMsgObj.id, newMsgObj.id, newMsgObj);
processSentMessage(newMsgObj.id);
if (newMsgObj.media instanceof TLRPC.TL_messageMediaVideo) {
stopVideoService(attachPath);
}
}
});
}
});
} else {
MessagesStorage.getInstance().markMessageAsSendError(newMsgObj.id);
AndroidUtilities.RunOnUIThread(new Runnable() { AndroidUtilities.RunOnUIThread(new Runnable() {
@Override @Override
public void run() { public void run() {
newMsgObj.send_state = MessageObject.MESSAGE_SEND_STATE_SENT; newMsgObj.send_state = MessageObject.MESSAGE_SEND_STATE_SEND_ERROR;
NotificationCenter.getInstance().postNotificationName(NotificationCenter.messageReceivedByServer, newMsgObj.id, newMsgObj.id, newMsgObj); NotificationCenter.getInstance().postNotificationName(NotificationCenter.messageSendError, newMsgObj.id);
processSentMessage(newMsgObj.id); processSentMessage(newMsgObj.id);
if (newMsgObj.media instanceof TLRPC.TL_messageMediaVideo) { if (newMsgObj.media instanceof TLRPC.TL_messageMediaVideo) {
stopVideoService(attachPath); stopVideoService(newMsgObj.attachPath);
} }
} }
}); });
} }
}); }
} else {
MessagesStorage.getInstance().markMessageAsSendError(newMsgObj.id);
AndroidUtilities.RunOnUIThread(new Runnable() {
@Override
public void run() {
newMsgObj.send_state = MessageObject.MESSAGE_SEND_STATE_SEND_ERROR;
NotificationCenter.getInstance().postNotificationName(NotificationCenter.messageSendError, newMsgObj.id);
processSentMessage(newMsgObj.id);
if (newMsgObj.media instanceof TLRPC.TL_messageMediaVideo) {
stopVideoService(newMsgObj.attachPath);
}
}
});
} }
} });
} }
}); });
} }

View File

@ -14,7 +14,6 @@ import android.content.pm.PackageInfo;
import android.net.ConnectivityManager; import android.net.ConnectivityManager;
import android.net.NetworkInfo; import android.net.NetworkInfo;
import android.os.Build; import android.os.Build;
import android.os.PowerManager;
import android.util.Base64; import android.util.Base64;
import org.telegram.android.AndroidUtilities; import org.telegram.android.AndroidUtilities;
@ -83,8 +82,6 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection.
private volatile long nextCallToken = 1; private volatile long nextCallToken = 1;
private PowerManager.WakeLock wakeLock = null;
private static volatile ConnectionsManager Instance = null; private static volatile ConnectionsManager Instance = null;
public static ConnectionsManager getInstance() { public static ConnectionsManager getInstance() {
ConnectionsManager localInstance = Instance; ConnectionsManager localInstance = Instance;
@ -217,10 +214,6 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection.
} }
Utilities.stageQueue.postRunnable(stageRunnable, 1000); Utilities.stageQueue.postRunnable(stageRunnable, 1000);
PowerManager pm = (PowerManager)ApplicationLoader.applicationContext.getSystemService(Context.POWER_SERVICE);
wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "lock");
wakeLock.setReferenceCounted(false);
} }
public int getConnectionState() { public int getConnectionState() {
@ -2139,14 +2132,6 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection.
} else { } else {
if (resultContainer.result instanceof TLRPC.updates_Difference) { if (resultContainer.result instanceof TLRPC.updates_Difference) {
pushMessagesReceived = true; pushMessagesReceived = true;
AndroidUtilities.RunOnUIThread(new Runnable() {
@Override
public void run() {
if (wakeLock.isHeld()) {
wakeLock.release();
}
}
});
} }
request.completionBlock.run(resultContainer.result, null); request.completionBlock.run(resultContainer.result, null);
} }
@ -2317,23 +2302,9 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection.
if (paused) { if (paused) {
pushMessagesReceived = false; pushMessagesReceived = false;
} }
AndroidUtilities.RunOnUIThread(new Runnable() {
@Override
public void run() {
wakeLock.acquire(20000);
}
});
resumeNetworkInternal(); resumeNetworkInternal();
} else { } else {
pushMessagesReceived = true; pushMessagesReceived = true;
AndroidUtilities.RunOnUIThread(new Runnable() {
@Override
public void run() {
if (wakeLock.isHeld()) {
wakeLock.release();
}
}
});
MessagesController.getInstance().processUpdates((TLRPC.Updates) message, false); MessagesController.getInstance().processUpdates((TLRPC.Updates) message, false);
} }
} else { } else {

View File

@ -371,6 +371,7 @@ public class TLClassStore {
classStore.put(TLRPC.TL_userForeign_old.constructor, TLRPC.TL_userForeign_old.class); classStore.put(TLRPC.TL_userForeign_old.constructor, TLRPC.TL_userForeign_old.class);
classStore.put(TLRPC.TL_userDeleted_old.constructor, TLRPC.TL_userDeleted_old.class); classStore.put(TLRPC.TL_userDeleted_old.constructor, TLRPC.TL_userDeleted_old.class);
classStore.put(TLRPC.TL_messageEncryptedAction.constructor, TLRPC.TL_messageEncryptedAction.class); classStore.put(TLRPC.TL_messageEncryptedAction.constructor, TLRPC.TL_messageEncryptedAction.class);
classStore.put(TLRPC.TL_decryptedMessageHolder.constructor, TLRPC.TL_decryptedMessageHolder.class);
} }
static TLClassStore store = null; static TLClassStore store = null;

View File

@ -8431,6 +8431,35 @@ public class TLRPC {
//manually created //manually created
public static class TL_decryptedMessageHolder extends TLObject {
public static int constructor = 0x555555F9;
public long random_id;
public int date;
public TL_decryptedMessageLayer layer;
public EncryptedFile file;
public void readParams(AbsSerializedData stream) {
random_id = stream.readInt64();
date = stream.readInt32();
layer = (TL_decryptedMessageLayer)TLClassStore.Instance().TLdeserialize(stream, stream.readInt32());
if (stream.readBool()) {
file = (EncryptedFile) TLClassStore.Instance().TLdeserialize(stream, stream.readInt32());
}
}
public void serializeToStream(AbsSerializedData stream) {
stream.writeInt32(constructor);
stream.writeInt64(random_id);
stream.writeInt32(date);
layer.serializeToStream(stream);
stream.writeBool(file != null);
if (file != null) {
file.serializeToStream(stream);
}
}
}
public static class TL_messages_sendEncryptedService extends TLObject { public static class TL_messages_sendEncryptedService extends TLObject {
public static int constructor = 0x32d439a4; public static int constructor = 0x32d439a4;

View File

@ -1685,9 +1685,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
maxMessageId = Math.max(obj.messageOwner.id, maxMessageId); maxMessageId = Math.max(obj.messageOwner.id, maxMessageId);
minMessageId = Math.min(obj.messageOwner.id, minMessageId); minMessageId = Math.min(obj.messageOwner.id, minMessageId);
} }
maxDate = Math.max(maxDate, obj.messageOwner.date); if (obj.messageOwner.date != 0) {
if (minDate == 0 || obj.messageOwner.date < minDate) { maxDate = Math.max(maxDate, obj.messageOwner.date);
minDate = obj.messageOwner.date; if (minDate == 0 || obj.messageOwner.date < minDate) {
minDate = obj.messageOwner.date;
}
} }
if (obj.type < 0) { if (obj.type < 0) {

View File

@ -207,8 +207,11 @@ public class CountrySelectActivity extends BaseFragment {
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override @Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) { public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
if (i < 0) {
return;
}
if (searching && searchWas) { if (searching && searchWas) {
if (i < searchResult.size()) { if (i >= 0 && i < searchResult.size()) {
Country c = searchResult.get(i); Country c = searchResult.get(i);
if (delegate != null) { if (delegate != null) {
delegate.didSelectCountry(c.name); delegate.didSelectCountry(c.name);
@ -218,10 +221,10 @@ public class CountrySelectActivity extends BaseFragment {
} else { } else {
int section = listViewAdapter.getSectionForPosition(i); int section = listViewAdapter.getSectionForPosition(i);
int row = listViewAdapter.getPositionInSectionForPosition(i); int row = listViewAdapter.getPositionInSectionForPosition(i);
if (section < sortedCountries.size()) { if (section >= 0 && section < sortedCountries.size()) {
String n = sortedCountries.get(section); String n = sortedCountries.get(section);
ArrayList<Country> arr = countries.get(n); ArrayList<Country> arr = countries.get(n);
if (row < arr.size()) { if (row >= 0 && row < arr.size()) {
Country c = arr.get(row); Country c = arr.get(row);
if (delegate != null) { if (delegate != null) {
delegate.didSelectCountry(c.name); delegate.didSelectCountry(c.name);

View File

@ -18,8 +18,10 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.Canvas; import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PixelFormat; import android.graphics.PixelFormat;
import android.graphics.Rect; import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
@ -43,7 +45,6 @@ import android.view.animation.ScaleAnimation;
import android.widget.Button; import android.widget.Button;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.Scroller; import android.widget.Scroller;
import android.widget.TextView; import android.widget.TextView;
@ -60,8 +61,8 @@ import org.telegram.android.NotificationCenter;
import org.telegram.messenger.R; import org.telegram.messenger.R;
import org.telegram.messenger.TLRPC; import org.telegram.messenger.TLRPC;
import org.telegram.messenger.UserConfig; import org.telegram.messenger.UserConfig;
import org.telegram.messenger.Utilities;
import org.telegram.android.MessageObject; import org.telegram.android.MessageObject;
import org.telegram.messenger.Utilities;
import org.telegram.ui.Views.ActionBar.ActionBar; import org.telegram.ui.Views.ActionBar.ActionBar;
import org.telegram.ui.Views.ActionBar.ActionBarLayer; import org.telegram.ui.Views.ActionBar.ActionBarLayer;
import org.telegram.ui.Views.ActionBar.ActionBarMenu; import org.telegram.ui.Views.ActionBar.ActionBarMenu;
@ -96,17 +97,15 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
private TextView nameTextView; private TextView nameTextView;
private TextView dateTextView; private TextView dateTextView;
private ImageView deleteButton; private ImageView deleteButton;
private ProgressBar progressBar;
private ActionBarMenuItem menuItem; private ActionBarMenuItem menuItem;
private ColorDrawable backgroundDrawable = new ColorDrawable(0xff000000); private ColorDrawable backgroundDrawable = new ColorDrawable(0xff000000);
private OverlayView currentOverlay;
private ImageView checkImageView; private ImageView checkImageView;
private View pickerView; private View pickerView;
private TextView doneButtonTextView; private TextView doneButtonTextView;
private TextView doneButtonBadgeTextView; private TextView doneButtonBadgeTextView;
private ImageView shareButton; private ImageView shareButton;
private RadialProgressView radialProgressViews[] = new RadialProgressView[3];
private boolean canShowBottom = true; private boolean canShowBottom = true;
private boolean overlayViewVisible = true;
private int animationInProgress = 0; private int animationInProgress = 0;
private long transitionAnimationStartTime = 0; private long transitionAnimationStartTime = 0;
@ -122,7 +121,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
private int currentIndex; private int currentIndex;
private MessageObject currentMessageObject; private MessageObject currentMessageObject;
private TLRPC.FileLocation currentFileLocation; private TLRPC.FileLocation currentFileLocation;
private String currentFileName; private String currentFileNames[] = new String[3];
private PlaceProviderObject currentPlaceObject; private PlaceProviderObject currentPlaceObject;
private String currentPathObject; private String currentPathObject;
private Bitmap currentThumb = null; private Bitmap currentThumb = null;
@ -188,31 +187,100 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
private final static int PAGE_SPACING = AndroidUtilities.dp(30); private final static int PAGE_SPACING = AndroidUtilities.dp(30);
private static class OverlayView extends FrameLayout { private static class RadialProgressView {
public TextView actionButton; private long lastUpdateTime = 0;
private float radOffset = 0;
private float currentProgress = 0;
private float animationProgressStart = 0;
private long currentProgressTime = 0;
private float animatedProgressValue = 0;
private RectF progressRect = new RectF();
private int backgroundState = -1;
private View parent = null;
private int size = AndroidUtilities.dp(64);
public OverlayView(Context context) { private static DecelerateInterpolator decelerateInterpolator = null;
super(context); private static Paint progressPaint = null;
actionButton = new TextView(context); public RadialProgressView(Context context, View parentView) {
actionButton.setBackgroundResource(R.drawable.system_black); if (decelerateInterpolator == null) {
actionButton.setPadding(AndroidUtilities.dp(8), AndroidUtilities.dp(2), AndroidUtilities.dp(8), AndroidUtilities.dp(2)); decelerateInterpolator = new DecelerateInterpolator();
actionButton.setTextColor(0xffffffff); progressPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
actionButton.setTextSize(26); progressPaint.setStyle(Paint.Style.STROKE);
actionButton.setGravity(Gravity.CENTER); progressPaint.setStrokeCap(Paint.Cap.ROUND);
addView(actionButton); progressPaint.setStrokeWidth(AndroidUtilities.dp(2));
LayoutParams layoutParams = (LayoutParams)actionButton.getLayoutParams(); progressPaint.setColor(0xffffffff);
layoutParams.width = LayoutParams.WRAP_CONTENT; }
layoutParams.height = LayoutParams.WRAP_CONTENT; parent = parentView;
layoutParams.gravity = Gravity.CENTER; }
actionButton.setLayoutParams(layoutParams);
actionButton.setOnClickListener(new OnClickListener() { private void updateAnimation() {
@Override long newTime = System.currentTimeMillis();
public void onClick(View v) { long dt = newTime - lastUpdateTime;
getInstance().onActionClick(OverlayView.this); lastUpdateTime = newTime;
radOffset += 360 * dt / 3000.0f;
float progressDiff = currentProgress - animationProgressStart;
if (progressDiff > 0) {
currentProgressTime += dt;
if (currentProgressTime >= 300) {
animatedProgressValue = currentProgress;
animationProgressStart = currentProgress;
currentProgressTime = 0;
} else {
animatedProgressValue = animationProgressStart + progressDiff * decelerateInterpolator.getInterpolation(currentProgressTime / 300.0f);
} }
}); }
parent.invalidate();
}
public float getRadOffset() {
return radOffset;
}
public void setRadOffset(float value) {
radOffset = value;
}
public void setProgress(float value, boolean animated) {
if (!animated) {
animatedProgressValue = value;
animationProgressStart = value;
} else {
animationProgressStart = animatedProgressValue;
}
currentProgress = value;
currentProgressTime = 0;
}
public void setBackgroundState(int state) {
lastUpdateTime = System.currentTimeMillis();
backgroundState = state;
parent.invalidate();
}
public void onDraw(Canvas canvas) {
if (backgroundState < 0 || backgroundState > 3) {
return;
}
int x = (canvas.getWidth() - size) / 2;
int y = (canvas.getHeight() - size) / 2;
Drawable drawable = progressDrawables[backgroundState];
if (drawable != null) {
drawable.setBounds(x, y, x + size, y + size);
drawable.draw(canvas);
}
if (backgroundState == 0 || backgroundState == 1) {
int diff = AndroidUtilities.dp(1);
progressRect.set(x + diff, y + diff, x + size - diff, y + size - diff);
canvas.drawArc(progressRect, -90 + radOffset, Math.max(4, 360 * animatedProgressValue), false, progressPaint);
updateAnimation();
}
} }
} }
@ -294,31 +362,26 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
public void didReceivedNotification(int id, Object... args) { public void didReceivedNotification(int id, Object... args) {
if (id == NotificationCenter.FileDidFailedLoad) { if (id == NotificationCenter.FileDidFailedLoad) {
String location = (String)args[0]; String location = (String)args[0];
if (currentFileName != null && currentFileName.equals(location)) { for (int a = 0; a < 3; a++) {
progressBar.setVisibility(View.GONE); if (currentFileNames[a] != null && currentFileNames[a].equals(location)) {
updateActionOverlays(); checkProgress(a);
break;
}
} }
} else if (id == NotificationCenter.FileDidLoaded) { } else if (id == NotificationCenter.FileDidLoaded) {
String location = (String)args[0]; String location = (String)args[0];
if (currentFileName != null && currentFileName.equals(location)) { for (int a = 0; a < 3; a++) {
progressBar.setVisibility(View.GONE); if (currentFileNames[a] != null && currentFileNames[a].equals(location)) {
updateActionOverlays(); checkProgress(a);
break;
}
} }
} else if (id == NotificationCenter.FileLoadProgressChanged) { } else if (id == NotificationCenter.FileLoadProgressChanged) {
String location = (String)args[0]; String location = (String)args[0];
if (currentFileName != null && currentFileName.equals(location)) { for (int a = 0; a < 3; a++) {
Float progress = (Float)args[1]; if (currentFileNames[a] != null && currentFileNames[a].equals(location)) {
progressBar.setVisibility(View.VISIBLE); Float progress = (Float) args[1];
if (android.os.Build.VERSION.SDK_INT >= 11) { radialProgressViews[a].setProgress(progress, true);
progressBar.setProgress((int) (progress * 100));
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(
ObjectAnimator.ofInt(progressBar, "progress", (int) (progress * 100))
);
animatorSet.setDuration(400);
animatorSet.start();
} else {
progressBar.setProgress((int) (progress * 100));
} }
} }
} else if (id == NotificationCenter.userPhotosLoaded) { } else if (id == NotificationCenter.userPhotosLoaded) {
@ -370,7 +433,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
setImageIndex(0, true); setImageIndex(0, true);
} }
if (fromCache) { if (fromCache) {
MessagesController.getInstance().loadUserPhotos(avatarsUserId, 0, 30, 0, false, classGuid); MessagesController.getInstance().loadUserPhotos(avatarsUserId, 0, 80, 0, false, classGuid);
} }
} }
} else if (id == NotificationCenter.mediaCountDidLoaded) { } else if (id == NotificationCenter.mediaCountDidLoaded) {
@ -471,10 +534,10 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
if (progressDrawables == null) { if (progressDrawables == null) {
progressDrawables = new Drawable[4]; progressDrawables = new Drawable[4];
progressDrawables[0] = parentActivity.getDrawable(R.drawable.cancel_big); progressDrawables[0] = parentActivity.getResources().getDrawable(R.drawable.circle_big);
progressDrawables[1] = parentActivity.getDrawable(R.drawable.circle_big); progressDrawables[1] = parentActivity.getResources().getDrawable(R.drawable.cancel_big);
progressDrawables[2] = parentActivity.getDrawable(R.drawable.load_big); progressDrawables[2] = parentActivity.getResources().getDrawable(R.drawable.load_big);
progressDrawables[3] = parentActivity.getDrawable(R.drawable.play_big); progressDrawables[3] = parentActivity.getResources().getDrawable(R.drawable.play_big);
} }
scroller = new Scroller(activity); scroller = new Scroller(activity);
@ -529,7 +592,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
} }
if (f != null && f.exists()) { if (f != null && f.exists()) {
MediaController.saveFile(f.toString(), parentActivity, currentFileName.endsWith("mp4") ? 1 : 0, null); MediaController.saveFile(f.toString(), parentActivity, currentFileNames[0].endsWith("mp4") ? 1 : 0, null);
} }
} else if (id == gallery_menu_showall) { } else if (id == gallery_menu_showall) {
if (opennedFromMedia) { if (opennedFromMedia) {
@ -607,6 +670,13 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
bottomLayout.setLayoutParams(layoutParams); bottomLayout.setLayoutParams(layoutParams);
bottomLayout.setBackgroundColor(0x7F000000); bottomLayout.setBackgroundColor(0x7F000000);
radialProgressViews[0] = new RadialProgressView(containerView.getContext(), containerView);
radialProgressViews[0].setBackgroundState(0);
radialProgressViews[1] = new RadialProgressView(containerView.getContext(), containerView);
radialProgressViews[1].setBackgroundState(0);
radialProgressViews[2] = new RadialProgressView(containerView.getContext(), containerView);
radialProgressViews[2].setBackgroundState(0);
shareButton = new ImageView(containerView.getContext()); shareButton = new ImageView(containerView.getContext());
shareButton.setImageResource(R.drawable.ic_ab_share_white); shareButton.setImageResource(R.drawable.ic_ab_share_white);
shareButton.setScaleType(ImageView.ScaleType.CENTER); shareButton.setScaleType(ImageView.ScaleType.CENTER);
@ -797,20 +867,6 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
doneButtonTextView.setText(LocaleController.getString("Send", R.string.Send).toUpperCase()); doneButtonTextView.setText(LocaleController.getString("Send", R.string.Send).toUpperCase());
doneButtonBadgeTextView = (TextView)doneButton.findViewById(R.id.done_button_badge); doneButtonBadgeTextView = (TextView)doneButton.findViewById(R.id.done_button_badge);
progressBar = new ProgressBar(containerView.getContext(), null, android.R.attr.progressBarStyleHorizontal);
progressBar.setVisibility(View.GONE);
progressBar.setMax(100);
progressBar.setProgressDrawable(parentActivity.getResources().getDrawable(R.drawable.photo_progress));
containerView.addView(progressBar);
layoutParams = (FrameLayout.LayoutParams)progressBar.getLayoutParams();
layoutParams.width = FrameLayout.LayoutParams.MATCH_PARENT;
layoutParams.height = AndroidUtilities.dp(3);
layoutParams.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL;
layoutParams.leftMargin = AndroidUtilities.dp(6);
layoutParams.rightMargin = AndroidUtilities.dp(6);
layoutParams.bottomMargin = AndroidUtilities.dp(48);
progressBar.setLayoutParams(layoutParams);
gestureDetector = new GestureDetector(containerView.getContext(), this); gestureDetector = new GestureDetector(containerView.getContext(), this);
gestureDetector.setOnDoubleTapListener(this); gestureDetector.setOnDoubleTapListener(this);
@ -818,10 +874,6 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
leftImage.setParentView(containerView); leftImage.setParentView(containerView);
rightImage.setParentView(containerView); rightImage.setParentView(containerView);
currentOverlay = new OverlayView(containerView.getContext());
containerView.addView(currentOverlay);
currentOverlay.setVisibility(View.GONE);
checkImageView = new ImageView(containerView.getContext()); checkImageView = new ImageView(containerView.getContext());
containerView.addView(checkImageView); containerView.addView(checkImageView);
checkImageView.setVisibility(View.GONE); checkImageView.setVisibility(View.GONE);
@ -856,28 +908,6 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
}); });
} }
private void toggleOverlayView(boolean show) {
if (overlayViewVisible == show) {
return;
}
if (currentOverlay.getVisibility() == View.VISIBLE) {
overlayViewVisible = show;
if (android.os.Build.VERSION.SDK_INT >= 11) {
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(
ObjectAnimator.ofFloat(currentOverlay, "alpha", show ? 1.0f : 0.0f)
);
animatorSet.setDuration(200);
animatorSet.start();
} else {
AlphaAnimation animation = new AlphaAnimation(show ? 0.0f : 1.0f, show ? 1.0f : 0.0f);
animation.setDuration(200);
animation.setFillAfter(true);
currentOverlay.startAnimation(animation);
}
}
}
private void toggleActionBar(boolean show, boolean animated) { private void toggleActionBar(boolean show, boolean animated) {
if (show) { if (show) {
actionBar.setVisibility(View.VISIBLE); actionBar.setVisibility(View.VISIBLE);
@ -930,11 +960,11 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
} }
} }
private String getFileName(int index, TLRPC.InputFileLocation fileLocation) { private String getFileName(int index) {
if (index < 0) { if (index < 0) {
return null; return null;
} }
TLRPC.InputFileLocation file = fileLocation != null ? fileLocation : getInputFileLocation(index); TLRPC.InputFileLocation file = getInputFileLocation(index);
if (file == null) { if (file == null) {
return null; return null;
} }
@ -1084,56 +1114,15 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
} }
} }
private void updateActionOverlays() {
if (currentMessageObject == null || currentFileName == null) {
currentOverlay.setVisibility(View.GONE);
return;
}
if (currentFileName.endsWith("mp4")) {
if (!currentMessageObject.isSending() && !currentMessageObject.isSendError()) {
currentOverlay.setVisibility(View.VISIBLE);
boolean load = false;
if (currentMessageObject.messageOwner.attachPath != null && currentMessageObject.messageOwner.attachPath.length() != 0) {
File f = new File(currentMessageObject.messageOwner.attachPath);
if (f.exists()) {
currentOverlay.actionButton.setText(LocaleController.getString("ViewVideo", R.string.ViewVideo));
} else {
load = true;
}
} else {
File cacheFile = FileLoader.getPathToMessage(currentMessageObject.messageOwner);
if (cacheFile.exists()) {
currentOverlay.actionButton.setText(LocaleController.getString("ViewVideo", R.string.ViewVideo));
} else {
load = true;
}
}
if (load) {
if (FileLoader.getInstance().isLoadingFile(currentFileName)) {
Float progress = FileLoader.getInstance().getFileProgress(currentFileName);
currentOverlay.actionButton.setText(LocaleController.getString("CancelDownload", R.string.CancelDownload));
progressBar.setVisibility(View.VISIBLE);
if (progress != null) {
progressBar.setProgress((int)(progress * 100));
}
} else {
currentOverlay.actionButton.setText(String.format("%s %s", LocaleController.getString("DOWNLOAD", R.string.DOWNLOAD), Utilities.formatFileSize(currentMessageObject.messageOwner.media.video.size)));
progressBar.setVisibility(View.GONE);
}
}
}
} else {
currentOverlay.setVisibility(View.GONE);
}
}
private void onPhotoShow(final MessageObject messageObject, final TLRPC.FileLocation fileLocation, final ArrayList<MessageObject> messages, final ArrayList<MediaController.PhotoEntry> photos, int index, final PlaceProviderObject object) { private void onPhotoShow(final MessageObject messageObject, final TLRPC.FileLocation fileLocation, final ArrayList<MessageObject> messages, final ArrayList<MediaController.PhotoEntry> photos, int index, final PlaceProviderObject object) {
classGuid = ConnectionsManager.getInstance().generateClassGuid(); classGuid = ConnectionsManager.getInstance().generateClassGuid();
currentMessageObject = null; currentMessageObject = null;
currentFileLocation = null; currentFileLocation = null;
currentPathObject = null; currentPathObject = null;
currentIndex = -1; currentIndex = -1;
currentFileName = null; currentFileNames[0] = null;
currentFileNames[1] = null;
currentFileNames[2] = null;
avatarsUserId = 0; avatarsUserId = 0;
currentDialogId = 0; currentDialogId = 0;
totalImagesCount = 0; totalImagesCount = 0;
@ -1157,6 +1146,11 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
bottomLayout.setVisibility(View.VISIBLE); bottomLayout.setVisibility(View.VISIBLE);
checkImageView.setVisibility(View.GONE); checkImageView.setVisibility(View.GONE);
pickerView.setVisibility(View.GONE); pickerView.setVisibility(View.GONE);
for (int a = 0; a < 3; a++) {
if (radialProgressViews[a] != null) {
radialProgressViews[a].setBackgroundState(-1);
}
}
if (messageObject != null && messages == null) { if (messageObject != null && messages == null) {
imagesArr.add(messageObject); imagesArr.add(messageObject);
@ -1180,13 +1174,6 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
} else { } else {
menuItem.hideSubItem(gallery_menu_showall); menuItem.hideSubItem(gallery_menu_showall);
} }
if ((int) currentDialogId == 0) {
menuItem.hideSubItem(gallery_menu_save);
shareButton.setVisibility(View.GONE);
} else {
menuItem.showSubItem(gallery_menu_save);
shareButton.setVisibility(View.VISIBLE);
}
setImageIndex(0, true); setImageIndex(0, true);
} else if (fileLocation != null) { } else if (fileLocation != null) {
avatarsUserId = object.user_id; avatarsUserId = object.user_id;
@ -1223,13 +1210,6 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
} }
} }
} }
if ((int) currentDialogId == 0) {
menuItem.hideSubItem(gallery_menu_save);
shareButton.setVisibility(View.GONE);
} else {
menuItem.showSubItem(gallery_menu_save);
shareButton.setVisibility(View.VISIBLE);
}
opennedFromMedia = true; opennedFromMedia = true;
setImageIndex(index, true); setImageIndex(index, true);
} else if (photos != null) { } else if (photos != null) {
@ -1247,7 +1227,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
if (currentDialogId != 0 && totalImagesCount == 0) { if (currentDialogId != 0 && totalImagesCount == 0) {
MessagesController.getInstance().getMediaCount(currentDialogId, classGuid, true); MessagesController.getInstance().getMediaCount(currentDialogId, classGuid, true);
} else if (avatarsUserId != 0) { } else if (avatarsUserId != 0) {
MessagesController.getInstance().loadUserPhotos(avatarsUserId, 0, 30, 0, true, classGuid); MessagesController.getInstance().loadUserPhotos(avatarsUserId, 0, 80, 0, true, classGuid);
} }
} }
@ -1261,7 +1241,9 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
placeProvider.willSwitchFromPhoto(currentMessageObject, currentFileLocation, currentIndex); placeProvider.willSwitchFromPhoto(currentMessageObject, currentFileLocation, currentIndex);
int prevIndex = currentIndex; int prevIndex = currentIndex;
currentIndex = index; currentIndex = index;
currentFileName = getFileName(index, null); currentFileNames[0] = getFileName(index);
currentFileNames[1] = getFileName(index + 1);
currentFileNames[2] = getFileName(index - 1);
boolean sameImage = false; boolean sameImage = false;
if (!imagesArr.isEmpty()) { if (!imagesArr.isEmpty()) {
@ -1273,7 +1255,11 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
} else { } else {
nameTextView.setText(""); nameTextView.setText("");
} }
dateTextView.setText(LocaleController.formatterYearMax.format(((long) currentMessageObject.messageOwner.date) * 1000)); if (currentFileNames[0] != null && currentFileNames[0].endsWith("mp4")) {
dateTextView.setText(String.format("%s (%s)", LocaleController.formatterYearMax.format(((long) currentMessageObject.messageOwner.date) * 1000), Utilities.formatFileSize(currentMessageObject.messageOwner.media.video.size)));
} else {
dateTextView.setText(LocaleController.formatterYearMax.format(((long) currentMessageObject.messageOwner.date) * 1000));
}
if (totalImagesCount != 0 && !needSearchImageInArr) { if (totalImagesCount != 0 && !needSearchImageInArr) {
if (imagesArr.size() < totalImagesCount && !loadingMoreImages && currentIndex < 5) { if (imagesArr.size() < totalImagesCount && !loadingMoreImages && currentIndex < 5) {
@ -1283,6 +1269,13 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
} }
actionBarLayer.setTitle(LocaleController.formatString("Of", R.string.Of, (totalImagesCount - imagesArr.size()) + currentIndex + 1, totalImagesCount)); actionBarLayer.setTitle(LocaleController.formatString("Of", R.string.Of, (totalImagesCount - imagesArr.size()) + currentIndex + 1, totalImagesCount));
} }
if (currentMessageObject.messageOwner.ttl != 0) {
menuItem.hideSubItem(gallery_menu_save);
shareButton.setVisibility(View.GONE);
} else {
menuItem.showSubItem(gallery_menu_save);
shareButton.setVisibility(View.VISIBLE);
}
} else if (!imagesArrLocations.isEmpty()) { } else if (!imagesArrLocations.isEmpty()) {
nameTextView.setText(""); nameTextView.setText("");
dateTextView.setText(""); dateTextView.setText("");
@ -1297,6 +1290,8 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
sameImage = true; sameImage = true;
} }
actionBarLayer.setTitle(LocaleController.formatString("Of", R.string.Of, currentIndex + 1, imagesArrLocations.size())); actionBarLayer.setTitle(LocaleController.formatString("Of", R.string.Of, currentIndex + 1, imagesArrLocations.size()));
menuItem.showSubItem(gallery_menu_save);
shareButton.setVisibility(View.VISIBLE);
} else if (!imagesArrLocals.isEmpty()) { } else if (!imagesArrLocals.isEmpty()) {
currentPathObject = imagesArrLocals.get(index).path; currentPathObject = imagesArrLocals.get(index).path;
actionBarLayer.setTitle(LocaleController.formatString("Of", R.string.Of, currentIndex + 1, imagesArrLocals.size())); actionBarLayer.setTitle(LocaleController.formatString("Of", R.string.Of, currentIndex + 1, imagesArrLocals.size()));
@ -1351,7 +1346,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
canDragDown = true; canDragDown = true;
changingPage = false; changingPage = false;
switchImageAfterAnimation = 0; switchImageAfterAnimation = 0;
canZoom = currentFileName == null || !currentFileName.endsWith("mp4"); canZoom = currentFileNames[0] != null && !currentFileNames[0].endsWith("mp4") && radialProgressViews[0].backgroundState != 0;
updateMinMax(scale); updateMinMax(scale);
} }
@ -1366,45 +1361,66 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
centerImage = leftImage; centerImage = leftImage;
leftImage = temp; leftImage = temp;
setIndexToImage(leftImage, currentIndex - 1); setIndexToImage(leftImage, currentIndex - 1);
radialProgressViews[0].setRadOffset(radialProgressViews[2].getRadOffset());
} else if (prevIndex < currentIndex) { } else if (prevIndex < currentIndex) {
ImageReceiver temp = leftImage; ImageReceiver temp = leftImage;
leftImage = centerImage; leftImage = centerImage;
centerImage = rightImage; centerImage = rightImage;
rightImage = temp; rightImage = temp;
radialProgressViews[0].setRadOffset(radialProgressViews[1].getRadOffset());
setIndexToImage(rightImage, currentIndex + 1); setIndexToImage(rightImage, currentIndex + 1);
} }
} }
if (currentFileName != null) { for (int a = 0; a < 3; a++) {
checkProgress(a);
}
}
private void checkProgress(int a) {
if (currentFileNames[a] != null) {
int index = currentIndex;
if (a == 1) {
index += 1;
} else if (a == 2) {
index -= 1;
}
File f = null; File f = null;
if (currentMessageObject != null) { if (currentMessageObject != null) {
f = FileLoader.getPathToMessage(currentMessageObject.messageOwner); MessageObject messageObject = imagesArr.get(index);
f = FileLoader.getPathToMessage(messageObject.messageOwner);
} else if (currentFileLocation != null) { } else if (currentFileLocation != null) {
f = FileLoader.getPathToAttach(currentFileLocation, avatarsUserId != 0); TLRPC.FileLocation location = imagesArrLocations.get(index);
f = FileLoader.getPathToAttach(location, avatarsUserId != 0);
} }
if (f.exists()) { if (f != null && f.exists()) {
progressBar.setVisibility(View.GONE); if (currentFileNames[a].endsWith("mp4")) {
radialProgressViews[a].setBackgroundState(3);
} else {
radialProgressViews[a].setBackgroundState(-1);
}
} else { } else {
if (currentFileName.endsWith("mp4")) { if (currentFileNames[a].endsWith("mp4")) {
if (!FileLoader.getInstance().isLoadingFile(currentFileName)) { if (!FileLoader.getInstance().isLoadingFile(currentFileNames[a])) {
progressBar.setVisibility(View.GONE); radialProgressViews[a].setBackgroundState(2);
} else { } else {
progressBar.setVisibility(View.VISIBLE); radialProgressViews[a].setBackgroundState(1);
} }
} else { } else {
progressBar.setVisibility(View.VISIBLE); radialProgressViews[a].setBackgroundState(0);
} }
Float progress = FileLoader.getInstance().getFileProgress(currentFileName); Float progress = FileLoader.getInstance().getFileProgress(currentFileNames[a]);
if (progress != null) { if (progress == null) {
progressBar.setProgress((int)(progress * 100)); progress = 0.0f;
} else {
progressBar.setProgress(0);
} }
radialProgressViews[a].setProgress(progress, false);
}
if (a == 0) {
canZoom = currentFileNames[0] != null && !currentFileNames[0].endsWith("mp4") && radialProgressViews[0].backgroundState != 0;
} }
} else { } else {
progressBar.setVisibility(View.GONE); radialProgressViews[a].setBackgroundState(-1);
} }
updateActionOverlays();
} }
private void setIndexToImage(ImageReceiver imageReceiver, int index) { private void setIndexToImage(ImageReceiver imageReceiver, int index) {
@ -1546,7 +1562,6 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
isVisible = true; isVisible = true;
backgroundDrawable.setAlpha(255); backgroundDrawable.setAlpha(255);
toggleActionBar(true, false); toggleActionBar(true, false);
overlayViewVisible = true;
if(android.os.Build.VERSION.SDK_INT >= 11) { if(android.os.Build.VERSION.SDK_INT >= 11) {
AndroidUtilities.lockOrientation(parentActivity); AndroidUtilities.lockOrientation(parentActivity);
@ -1606,8 +1621,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
ObjectAnimator.ofInt(animatingImageView, "clipHorizontal", clipHorizontal, 0), ObjectAnimator.ofInt(animatingImageView, "clipHorizontal", clipHorizontal, 0),
ObjectAnimator.ofInt(animatingImageView, "clipTop", clipTop, 0), ObjectAnimator.ofInt(animatingImageView, "clipTop", clipTop, 0),
ObjectAnimator.ofInt(animatingImageView, "clipBottom", clipBottom, 0), ObjectAnimator.ofInt(animatingImageView, "clipBottom", clipBottom, 0),
ObjectAnimator.ofFloat(containerView, "alpha", 0.0f, 1.0f), ObjectAnimator.ofFloat(containerView, "alpha", 0.0f, 1.0f)
ObjectAnimator.ofFloat(currentOverlay, "alpha", 1.0f)
); );
animationEndRunnable = new Runnable() { animationEndRunnable = new Runnable() {
@ -1871,6 +1885,11 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
currentFileLocation = null; currentFileLocation = null;
currentPathObject = null; currentPathObject = null;
currentThumb = null; currentThumb = null;
for (int a = 0; a < 3; a++) {
if (radialProgressViews[a] != null) {
radialProgressViews[a].setBackgroundState(-1);
}
}
centerImage.setImageBitmap((Bitmap)null); centerImage.setImageBitmap((Bitmap)null);
leftImage.setImageBitmap((Bitmap)null); leftImage.setImageBitmap((Bitmap)null);
rightImage.setImageBitmap((Bitmap)null); rightImage.setImageBitmap((Bitmap)null);
@ -1987,7 +2006,6 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
} else if (draggingDown) { } else if (draggingDown) {
translationY = ev.getY() - dragY; translationY = ev.getY() - dragY;
containerView.invalidate(); containerView.invalidate();
toggleOverlayView(false);
} else if (!invalidCoords && animationStartTime == 0) { } else if (!invalidCoords && animationStartTime == 0) {
float moveDx = moveStartX - ev.getX(); float moveDx = moveStartX - ev.getX();
float moveDy = moveStartY - ev.getY(); float moveDy = moveStartY - ev.getY();
@ -1999,8 +2017,6 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
canDragDown = false; canDragDown = false;
} }
toggleOverlayView(false);
moveStartX = ev.getX(); moveStartX = ev.getX();
moveStartY = ev.getY(); moveStartY = ev.getY();
updateMinMax(scale); updateMinMax(scale);
@ -2145,9 +2161,6 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
} }
private void animateTo(float newScale, float newTx, float newTy, boolean isZoom) { private void animateTo(float newScale, float newTx, float newTy, boolean isZoom) {
if (switchImageAfterAnimation == 0) {
toggleOverlayView(true);
}
if (scale == newScale && translationX == newTx && translationY == newTy) { if (scale == newScale && translationX == newTx && translationY == newTy) {
AndroidUtilities.unlockOrientation(parentActivity); AndroidUtilities.unlockOrientation(parentActivity);
return; return;
@ -2227,7 +2240,6 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
setImageIndex(currentIndex - 1, false); setImageIndex(currentIndex - 1, false);
} }
switchImageAfterAnimation = 0; switchImageAfterAnimation = 0;
toggleOverlayView(true);
} }
canvas.translate(translationX, translationY); canvas.translate(translationX, translationY);
@ -2261,8 +2273,8 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
centerImage.draw(canvas); centerImage.draw(canvas);
} }
ImageReceiver sideImage = null;
if (scale >= 1.0f) { if (scale >= 1.0f) {
ImageReceiver sideImage = null;
float k = 1; float k = 1;
if (currentTranslationX > maxX + AndroidUtilities.dp(20)) { if (currentTranslationX > maxX + AndroidUtilities.dp(20)) {
k = -1; k = -1;
@ -2297,6 +2309,21 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
} }
canvas.restore(); canvas.restore();
canvas.save();
canvas.translate(currentTranslationX, currentTranslationY);
radialProgressViews[0].onDraw(canvas);
if (!zoomAnimation) {
if (sideImage == rightImage) {
canvas.translate((canvas.getWidth() * (scale + 1) + PAGE_SPACING) / 2, -currentTranslationY);
radialProgressViews[1].onDraw(canvas);
} else if (sideImage == leftImage) {
canvas.translate(-(canvas.getWidth() * (scale + 1) + PAGE_SPACING) / 2, -currentTranslationY);
radialProgressViews[2].onDraw(canvas);
}
}
canvas.restore();
} }
@SuppressLint("DrawAllocation") @SuppressLint("DrawAllocation")
@ -2328,8 +2355,8 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
} }
} }
private void onActionClick(View view) { private void onActionClick() {
if (currentMessageObject == null || currentFileName == null) { if (currentMessageObject == null || currentFileNames[0] == null) {
return; return;
} }
boolean loadFile = false; boolean loadFile = false;
@ -2353,12 +2380,11 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
} }
} }
if (loadFile) { if (loadFile) {
if (!FileLoader.getInstance().isLoadingFile(currentFileName)) { if (!FileLoader.getInstance().isLoadingFile(currentFileNames[0])) {
FileLoader.getInstance().loadFile(currentMessageObject.messageOwner.media.video, true); FileLoader.getInstance().loadFile(currentMessageObject.messageOwner.media.video, true);
} else { } else {
FileLoader.getInstance().cancelLoadFile(currentMessageObject.messageOwner.media.video); FileLoader.getInstance().cancelLoadFile(currentMessageObject.messageOwner.media.video);
} }
updateActionOverlays();
} }
} }
@ -2400,6 +2426,19 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
@Override @Override
public boolean onSingleTapConfirmed(MotionEvent e) { public boolean onSingleTapConfirmed(MotionEvent e) {
if (canShowBottom) { if (canShowBottom) {
if (radialProgressViews[0] != null && containerView != null) {
int state = radialProgressViews[0].backgroundState;
if (state > 0 && state <= 3) {
float x = e.getX();
float y = e.getY();
if (x >= (containerView.getWidth() - AndroidUtilities.dp(64)) / 2.0f && x <= (containerView.getWidth() + AndroidUtilities.dp(64)) / 2.0f &&
y >= (containerView.getHeight() - AndroidUtilities.dp(64)) / 2.0f && y <= (containerView.getHeight() + AndroidUtilities.dp(64)) / 2.0f) {
onActionClick();
checkProgress(0);
return true;
}
}
}
toggleActionBar(!isActionBarVisible, true); toggleActionBar(!isActionBarVisible, true);
} else { } else {
checkImageView.performClick(); checkImageView.performClick();