Bug fixes
This commit is contained in:
parent
3cd9b847e1
commit
a4af1fb2f7
@ -80,7 +80,7 @@ android {
|
||||
defaultConfig {
|
||||
minSdkVersion 8
|
||||
targetSdkVersion 19
|
||||
versionCode 374
|
||||
versionName "1.9.6"
|
||||
versionCode 377
|
||||
versionName "1.9.7"
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ LOCAL_PRELINK_MODULE := false
|
||||
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 += -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_LDLIBS := -llog
|
||||
LOCAL_LDLIBS := -ljnigraphics -llog
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -107,9 +107,9 @@ extern "C" {
|
||||
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
|
||||
** [sqlite_version()] and [sqlite_source_id()].
|
||||
*/
|
||||
#define SQLITE_VERSION "3.8.6"
|
||||
#define SQLITE_VERSION_NUMBER 3008006
|
||||
#define SQLITE_SOURCE_ID "2014-08-15 11:46:33 9491ba7d738528f168657adb43a198238abde19e"
|
||||
#define SQLITE_VERSION "3.8.7"
|
||||
#define SQLITE_VERSION_NUMBER 3008007
|
||||
#define SQLITE_SOURCE_ID "2014-10-17 11:24:17 e4ab094f8afce0817f4074e823fabe59fc29ebb4"
|
||||
|
||||
/*
|
||||
** 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_ROLLBACK (SQLITE_NOTICE | (2<<8))
|
||||
#define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1<<8))
|
||||
#define SQLITE_AUTH_USER (SQLITE_AUTH | (1<<8))
|
||||
|
||||
/*
|
||||
** 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.
|
||||
**
|
||||
** ^(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
|
||||
** 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
|
||||
** 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
|
||||
** by sqlite3_malloc() or sqlite3_realloc() releases that memory so
|
||||
** 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
|
||||
** was not obtained from sqlite3_malloc() or sqlite3_realloc().
|
||||
**
|
||||
** ^(The sqlite3_realloc() interface attempts to resize a
|
||||
** prior memory allocation to be at least N bytes, where N is the
|
||||
** second parameter. The memory allocation to be resized is the first
|
||||
** parameter.)^ ^ If the first parameter to sqlite3_realloc()
|
||||
** ^The sqlite3_realloc(X,N) interface attempts to resize a
|
||||
** prior memory allocation X to be at least N bytes.
|
||||
** ^If the X parameter to sqlite3_realloc(X,N)
|
||||
** is a NULL pointer then its behavior is identical to calling
|
||||
** sqlite3_malloc(N) where N is the second parameter to sqlite3_realloc().
|
||||
** ^If the second parameter to sqlite3_realloc() is zero or
|
||||
** sqlite3_malloc(N).
|
||||
** ^If the N parameter to sqlite3_realloc(X,N) is zero or
|
||||
** negative then the behavior is exactly the same as calling
|
||||
** sqlite3_free(P) where P is the first parameter to sqlite3_realloc().
|
||||
** ^sqlite3_realloc() returns a pointer to a memory allocation
|
||||
** of at least N bytes in size or NULL if sufficient memory is unavailable.
|
||||
** sqlite3_free(X).
|
||||
** ^sqlite3_realloc(X,N) returns a pointer to a memory allocation
|
||||
** 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
|
||||
** of the prior allocation are copied into the beginning of buffer returned
|
||||
** by sqlite3_realloc() and the prior allocation is freed.
|
||||
** ^If sqlite3_realloc() returns NULL, then the prior allocation
|
||||
** is not freed.
|
||||
** by sqlite3_realloc(X,N) and the prior allocation is freed.
|
||||
** ^If sqlite3_realloc(X,N) returns NULL and N is positive, then the
|
||||
** 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
|
||||
** 4 byte boundary if the [SQLITE_4_BYTE_ALIGNED_MALLOC] compile-time
|
||||
** option is used.
|
||||
@ -2359,8 +2378,11 @@ SQLITE_API char *sqlite3_vsnprintf(int,char*,const char*, va_list);
|
||||
** [sqlite3_free()] or [sqlite3_realloc()].
|
||||
*/
|
||||
SQLITE_API void *sqlite3_malloc(int);
|
||||
SQLITE_API void *sqlite3_malloc64(sqlite3_uint64);
|
||||
SQLITE_API void *sqlite3_realloc(void*, int);
|
||||
SQLITE_API void *sqlite3_realloc64(void*, sqlite3_uint64);
|
||||
SQLITE_API void sqlite3_free(void*);
|
||||
SQLITE_API sqlite3_uint64 sqlite3_msize(void*);
|
||||
|
||||
/*
|
||||
** 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
|
||||
** of the sqlite3_open() routines.
|
||||
**
|
||||
** ^The default encoding for the database will be UTF-8 if
|
||||
** sqlite3_open() or sqlite3_open_v2() is called and
|
||||
** UTF-16 in the native byte order if sqlite3_open16() is used.
|
||||
** ^The default encoding will be UTF-8 for databases created using
|
||||
** sqlite3_open() or sqlite3_open_v2(). ^The default encoding for databases
|
||||
** created using sqlite3_open16() will be UTF-16 in the native byte order.
|
||||
**
|
||||
** Whether or not an error occurs when it is opened, resources
|
||||
** 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
|
||||
** with a '/' (meaning that the authority section is omitted from the URI)
|
||||
** then the path is interpreted as a relative path.
|
||||
** ^On windows, the first component of an absolute path
|
||||
** is a drive specification (e.g. "C:").
|
||||
** ^(On windows, the first component of an absolute path
|
||||
** is a drive specification (e.g. "C:").)^
|
||||
**
|
||||
** [[core URI query parameters]]
|
||||
** The query component of a URI may contain parameters that are interpreted
|
||||
** 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>
|
||||
** <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
|
||||
** SQLITE_OPEN_PRIVATECACHE or SQLITE_OPEN_SHAREDCACHE flag.
|
||||
**
|
||||
** <li> <b>psow</b>: ^The psow parameter may be "true" (or "on" or "yes" or
|
||||
** "1") or "false" (or "off" or "no" or "0") to indicate that the
|
||||
** <li> <b>psow</b>: ^The psow parameter indicates whether or not the
|
||||
** [powersafe overwrite] property does or does not apply to the
|
||||
** storage media on which the database file resides. ^The psow query
|
||||
** parameter only works for the built-in unix and Windows VFSes.
|
||||
** storage media on which the database file resides.
|
||||
**
|
||||
** <li> <b>nolock</b>: ^The nolock parameter is a boolean query parameter
|
||||
** 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>
|
||||
** <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>
|
||||
*/
|
||||
#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_VARIABLE_NUMBER 9
|
||||
#define SQLITE_LIMIT_TRIGGER_DEPTH 10
|
||||
#define SQLITE_LIMIT_WORKER_THREADS 11
|
||||
|
||||
/*
|
||||
** 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
|
||||
** the behavior is undefined.
|
||||
** 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
|
||||
** terminated. If any NUL characters occur at byte offsets less than
|
||||
** the value of the fourth parameter then the resulting string value will
|
||||
** contain embedded NULs. The result of expressions involving strings
|
||||
** with embedded NULs is undefined.
|
||||
**
|
||||
** ^The fifth argument to sqlite3_bind_blob(), sqlite3_bind_text(), and
|
||||
** sqlite3_bind_text16() is a destructor used to dispose of the BLOB or
|
||||
** ^The fifth argument to the BLOB and string binding interfaces
|
||||
** is a destructor used to dispose of the BLOB or
|
||||
** 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(),
|
||||
** sqlite3_bind_text(), or sqlite3_bind_text16() fails.
|
||||
** to dispose of the BLOB or string even if the call to bind API fails.
|
||||
** ^If the fifth argument is
|
||||
** the special value [SQLITE_STATIC], then SQLite assumes that the
|
||||
** 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
|
||||
** 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
|
||||
** is filled with zeroes. ^A zeroblob uses a fixed amount of memory
|
||||
** (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
|
||||
** [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
|
||||
** 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()].
|
||||
*/
|
||||
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_int(sqlite3_stmt*, int, int);
|
||||
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_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_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_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.
|
||||
**
|
||||
** ^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.
|
||||
**
|
||||
** ^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
|
||||
** a text string which is represented as UTF-8, UTF-16 native byte order,
|
||||
** 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
|
||||
** the 2nd parameter of 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.
|
||||
*/
|
||||
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_error(sqlite3_context*, const char*, 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_null(sqlite3_context*);
|
||||
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_text16le(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_SCRATCHMALLOC 17
|
||||
#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_VDBE_COVERAGE 21
|
||||
#define SQLITE_TESTCTRL_BYTEORDER 22
|
||||
#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
|
||||
@ -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.)^
|
||||
**
|
||||
** [[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.)^
|
||||
** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0.
|
||||
**
|
||||
** [[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
|
||||
** with the connection - main, temp, and any [ATTACH]-ed databases.)^
|
||||
** ^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.
|
||||
**
|
||||
** [[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
|
||||
** the database connection.)^
|
||||
** ^The highwater mark associated with SQLITE_DBSTATUS_STMT_USED is always 0.
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -70,6 +70,8 @@ public class MessagesController implements NotificationCenter.NotificationCenter
|
||||
private ArrayList<Integer> loadingFullUsers = 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 int currentDeletingTaskTime = 0;
|
||||
private ArrayList<Integer> currentDeletingTaskMids = null;
|
||||
@ -322,6 +324,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter
|
||||
sendingTypings.clear();
|
||||
loadingFullUsers.clear();
|
||||
loadedFullUsers.clear();
|
||||
secretHolesQueue.clear();
|
||||
|
||||
updatesStartWaitTime = 0;
|
||||
currentDeletingTaskTime = 0;
|
||||
@ -3170,15 +3173,17 @@ public class MessagesController implements NotificationCenter.NotificationCenter
|
||||
}
|
||||
} else {
|
||||
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() {
|
||||
@Override
|
||||
public void run() {
|
||||
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);
|
||||
}
|
||||
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) {
|
||||
final TLRPC.EncryptedChat chat = getEncryptedChatDB(message.chat_id);
|
||||
if (chat == null || chat instanceof TLRPC.TL_encryptedChatDiscarded) {
|
||||
@ -3574,292 +3880,55 @@ public class MessagesController implements NotificationCenter.NotificationCenter
|
||||
int len = is.readInt32();
|
||||
TLObject object = TLClassStore.Instance().TLdeserialize(is, is.readInt32());
|
||||
BuffersStorage.getInstance().reuseFreeBuffer(is);
|
||||
if (object != null) {
|
||||
int from_id = chat.admin_id;
|
||||
if (from_id == UserConfig.getClientUserId()) {
|
||||
from_id = chat.participant_id;
|
||||
}
|
||||
|
||||
if (object instanceof TLRPC.TL_decryptedMessageLayer) {
|
||||
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 (object instanceof TLRPC.TL_decryptedMessageLayer) {
|
||||
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() {
|
||||
@Override
|
||||
public void run() {
|
||||
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;
|
||||
putEncryptedChat(newChat, false);
|
||||
MessagesStorage.getInstance().updateEncryptedChat(newChat);
|
||||
AndroidUtilities.RunOnUIThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
putEncryptedChat(newChat, false);
|
||||
NotificationCenter.getInstance().postNotificationName(NotificationCenter.encryptedChatUpdated, newChat);
|
||||
}
|
||||
});
|
||||
declineSecretChat(chat.id);
|
||||
NotificationCenter.getInstance().postNotificationName(NotificationCenter.encryptedChatUpdated, newChat);
|
||||
}
|
||||
});
|
||||
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;
|
||||
MessagesStorage.getInstance().updateEncryptedChatSeq(chat);
|
||||
object = layer.message;
|
||||
TLRPC.TL_decryptedMessageHolder holder = new TLRPC.TL_decryptedMessageHolder();
|
||||
holder.layer = layer;
|
||||
holder.file = message.file;
|
||||
holder.random_id = message.random_id;
|
||||
holder.date = message.date;
|
||||
arr.add(holder);
|
||||
return null;
|
||||
}
|
||||
|
||||
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 = 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");
|
||||
chat.seq_in = layer.out_seq_no;
|
||||
MessagesStorage.getInstance().updateEncryptedChatSeq(chat);
|
||||
object = layer.message;
|
||||
}
|
||||
return processDecryptedObject(chat, message.file, message.date, message.random_id, object);
|
||||
} else {
|
||||
BuffersStorage.getInstance().reuseFreeBuffer(is);
|
||||
FileLog.e("tmessages", "fingerprint mismatch");
|
||||
|
@ -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 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 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();
|
||||
|
||||
@ -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("PRAGMA user_version = 7").stepThis().dispose();
|
||||
database.executeFast("PRAGMA user_version = 8").stepThis().dispose();
|
||||
} else {
|
||||
try {
|
||||
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");
|
||||
if (version < 7) {
|
||||
if (version < 8) {
|
||||
updateDbToLastVersion(version);
|
||||
}
|
||||
}
|
||||
@ -303,6 +304,11 @@ public class MessagesStorage {
|
||||
database.executeFast("PRAGMA user_version = 7").stepThis().dispose();
|
||||
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) {
|
||||
FileLog.e("tmessages", e);
|
||||
}
|
||||
@ -665,6 +671,7 @@ public class MessagesStorage {
|
||||
}
|
||||
} else {
|
||||
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();
|
||||
@ -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) {
|
||||
storageQueue.postRunnable(new Runnable() {
|
||||
@Override
|
||||
|
@ -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) {
|
||||
return;
|
||||
}
|
||||
TLObject toEncryptObject = null;
|
||||
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() {
|
||||
Utilities.stageQueue.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run(TLObject response, TLRPC.TL_error error) {
|
||||
if (error == null) {
|
||||
if (req.action instanceof TLRPC.TL_decryptedMessageActionNotifyLayer) {
|
||||
AndroidUtilities.RunOnUIThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
public void run() {
|
||||
TLObject toEncryptObject = null;
|
||||
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
|
||||
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);
|
||||
sendingNotifyLayer.remove((Integer)currentChat.id);
|
||||
currentChat.layer = AndroidUtilities.setMyLayerVersion(currentChat.layer, CURRENT_SECRET_CHAT_LAYER);
|
||||
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) {
|
||||
processSentMessage(newMsgObj, null, res.file, req, originalPath);
|
||||
}
|
||||
MessagesStorage.getInstance().storageQueue.postRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
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)) {
|
||||
res.date = 0;
|
||||
if (newMsgObj.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionScreenshotMessages || newMsgObj.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionSetMessageTTL) {
|
||||
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() {
|
||||
@Override
|
||||
public void run() {
|
||||
newMsgObj.send_state = MessageObject.MESSAGE_SEND_STATE_SENT;
|
||||
NotificationCenter.getInstance().postNotificationName(NotificationCenter.messageReceivedByServer, newMsgObj.id, newMsgObj.id, newMsgObj);
|
||||
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(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);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -14,7 +14,6 @@ import android.content.pm.PackageInfo;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.NetworkInfo;
|
||||
import android.os.Build;
|
||||
import android.os.PowerManager;
|
||||
import android.util.Base64;
|
||||
|
||||
import org.telegram.android.AndroidUtilities;
|
||||
@ -83,8 +82,6 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection.
|
||||
|
||||
private volatile long nextCallToken = 1;
|
||||
|
||||
private PowerManager.WakeLock wakeLock = null;
|
||||
|
||||
private static volatile ConnectionsManager Instance = null;
|
||||
public static ConnectionsManager getInstance() {
|
||||
ConnectionsManager localInstance = Instance;
|
||||
@ -217,10 +214,6 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection.
|
||||
}
|
||||
|
||||
Utilities.stageQueue.postRunnable(stageRunnable, 1000);
|
||||
|
||||
PowerManager pm = (PowerManager)ApplicationLoader.applicationContext.getSystemService(Context.POWER_SERVICE);
|
||||
wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "lock");
|
||||
wakeLock.setReferenceCounted(false);
|
||||
}
|
||||
|
||||
public int getConnectionState() {
|
||||
@ -2139,14 +2132,6 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection.
|
||||
} else {
|
||||
if (resultContainer.result instanceof TLRPC.updates_Difference) {
|
||||
pushMessagesReceived = true;
|
||||
AndroidUtilities.RunOnUIThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (wakeLock.isHeld()) {
|
||||
wakeLock.release();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
request.completionBlock.run(resultContainer.result, null);
|
||||
}
|
||||
@ -2317,23 +2302,9 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection.
|
||||
if (paused) {
|
||||
pushMessagesReceived = false;
|
||||
}
|
||||
AndroidUtilities.RunOnUIThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
wakeLock.acquire(20000);
|
||||
}
|
||||
});
|
||||
resumeNetworkInternal();
|
||||
} else {
|
||||
pushMessagesReceived = true;
|
||||
AndroidUtilities.RunOnUIThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (wakeLock.isHeld()) {
|
||||
wakeLock.release();
|
||||
}
|
||||
}
|
||||
});
|
||||
MessagesController.getInstance().processUpdates((TLRPC.Updates) message, false);
|
||||
}
|
||||
} else {
|
||||
|
@ -371,6 +371,7 @@ public class TLClassStore {
|
||||
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_messageEncryptedAction.constructor, TLRPC.TL_messageEncryptedAction.class);
|
||||
classStore.put(TLRPC.TL_decryptedMessageHolder.constructor, TLRPC.TL_decryptedMessageHolder.class);
|
||||
}
|
||||
|
||||
static TLClassStore store = null;
|
||||
|
@ -8431,6 +8431,35 @@ public class TLRPC {
|
||||
|
||||
//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 int constructor = 0x32d439a4;
|
||||
|
||||
|
@ -1685,9 +1685,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
|
||||
maxMessageId = Math.max(obj.messageOwner.id, maxMessageId);
|
||||
minMessageId = Math.min(obj.messageOwner.id, minMessageId);
|
||||
}
|
||||
maxDate = Math.max(maxDate, obj.messageOwner.date);
|
||||
if (minDate == 0 || obj.messageOwner.date < minDate) {
|
||||
minDate = obj.messageOwner.date;
|
||||
if (obj.messageOwner.date != 0) {
|
||||
maxDate = Math.max(maxDate, obj.messageOwner.date);
|
||||
if (minDate == 0 || obj.messageOwner.date < minDate) {
|
||||
minDate = obj.messageOwner.date;
|
||||
}
|
||||
}
|
||||
|
||||
if (obj.type < 0) {
|
||||
|
@ -207,8 +207,11 @@ public class CountrySelectActivity extends BaseFragment {
|
||||
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
|
||||
if (i < 0) {
|
||||
return;
|
||||
}
|
||||
if (searching && searchWas) {
|
||||
if (i < searchResult.size()) {
|
||||
if (i >= 0 && i < searchResult.size()) {
|
||||
Country c = searchResult.get(i);
|
||||
if (delegate != null) {
|
||||
delegate.didSelectCountry(c.name);
|
||||
@ -218,10 +221,10 @@ public class CountrySelectActivity extends BaseFragment {
|
||||
} else {
|
||||
int section = listViewAdapter.getSectionForPosition(i);
|
||||
int row = listViewAdapter.getPositionInSectionForPosition(i);
|
||||
if (section < sortedCountries.size()) {
|
||||
if (section >= 0 && section < sortedCountries.size()) {
|
||||
String n = sortedCountries.get(section);
|
||||
ArrayList<Country> arr = countries.get(n);
|
||||
if (row < arr.size()) {
|
||||
if (row >= 0 && row < arr.size()) {
|
||||
Country c = arr.get(row);
|
||||
if (delegate != null) {
|
||||
delegate.didSelectCountry(c.name);
|
||||
|
@ -18,8 +18,10 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
@ -43,7 +45,6 @@ import android.view.animation.ScaleAnimation;
|
||||
import android.widget.Button;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.Scroller;
|
||||
import android.widget.TextView;
|
||||
|
||||
@ -60,8 +61,8 @@ import org.telegram.android.NotificationCenter;
|
||||
import org.telegram.messenger.R;
|
||||
import org.telegram.messenger.TLRPC;
|
||||
import org.telegram.messenger.UserConfig;
|
||||
import org.telegram.messenger.Utilities;
|
||||
import org.telegram.android.MessageObject;
|
||||
import org.telegram.messenger.Utilities;
|
||||
import org.telegram.ui.Views.ActionBar.ActionBar;
|
||||
import org.telegram.ui.Views.ActionBar.ActionBarLayer;
|
||||
import org.telegram.ui.Views.ActionBar.ActionBarMenu;
|
||||
@ -96,17 +97,15 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
|
||||
private TextView nameTextView;
|
||||
private TextView dateTextView;
|
||||
private ImageView deleteButton;
|
||||
private ProgressBar progressBar;
|
||||
private ActionBarMenuItem menuItem;
|
||||
private ColorDrawable backgroundDrawable = new ColorDrawable(0xff000000);
|
||||
private OverlayView currentOverlay;
|
||||
private ImageView checkImageView;
|
||||
private View pickerView;
|
||||
private TextView doneButtonTextView;
|
||||
private TextView doneButtonBadgeTextView;
|
||||
private ImageView shareButton;
|
||||
private RadialProgressView radialProgressViews[] = new RadialProgressView[3];
|
||||
private boolean canShowBottom = true;
|
||||
private boolean overlayViewVisible = true;
|
||||
|
||||
private int animationInProgress = 0;
|
||||
private long transitionAnimationStartTime = 0;
|
||||
@ -122,7 +121,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
|
||||
private int currentIndex;
|
||||
private MessageObject currentMessageObject;
|
||||
private TLRPC.FileLocation currentFileLocation;
|
||||
private String currentFileName;
|
||||
private String currentFileNames[] = new String[3];
|
||||
private PlaceProviderObject currentPlaceObject;
|
||||
private String currentPathObject;
|
||||
private Bitmap currentThumb = null;
|
||||
@ -188,31 +187,100 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
|
||||
|
||||
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) {
|
||||
super(context);
|
||||
private static DecelerateInterpolator decelerateInterpolator = null;
|
||||
private static Paint progressPaint = null;
|
||||
|
||||
actionButton = new TextView(context);
|
||||
actionButton.setBackgroundResource(R.drawable.system_black);
|
||||
actionButton.setPadding(AndroidUtilities.dp(8), AndroidUtilities.dp(2), AndroidUtilities.dp(8), AndroidUtilities.dp(2));
|
||||
actionButton.setTextColor(0xffffffff);
|
||||
actionButton.setTextSize(26);
|
||||
actionButton.setGravity(Gravity.CENTER);
|
||||
addView(actionButton);
|
||||
LayoutParams layoutParams = (LayoutParams)actionButton.getLayoutParams();
|
||||
layoutParams.width = LayoutParams.WRAP_CONTENT;
|
||||
layoutParams.height = LayoutParams.WRAP_CONTENT;
|
||||
layoutParams.gravity = Gravity.CENTER;
|
||||
actionButton.setLayoutParams(layoutParams);
|
||||
actionButton.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
getInstance().onActionClick(OverlayView.this);
|
||||
public RadialProgressView(Context context, View parentView) {
|
||||
if (decelerateInterpolator == null) {
|
||||
decelerateInterpolator = new DecelerateInterpolator();
|
||||
progressPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
progressPaint.setStyle(Paint.Style.STROKE);
|
||||
progressPaint.setStrokeCap(Paint.Cap.ROUND);
|
||||
progressPaint.setStrokeWidth(AndroidUtilities.dp(2));
|
||||
progressPaint.setColor(0xffffffff);
|
||||
}
|
||||
parent = parentView;
|
||||
}
|
||||
|
||||
private void updateAnimation() {
|
||||
long newTime = System.currentTimeMillis();
|
||||
long dt = newTime - lastUpdateTime;
|
||||
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) {
|
||||
if (id == NotificationCenter.FileDidFailedLoad) {
|
||||
String location = (String)args[0];
|
||||
if (currentFileName != null && currentFileName.equals(location)) {
|
||||
progressBar.setVisibility(View.GONE);
|
||||
updateActionOverlays();
|
||||
for (int a = 0; a < 3; a++) {
|
||||
if (currentFileNames[a] != null && currentFileNames[a].equals(location)) {
|
||||
checkProgress(a);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (id == NotificationCenter.FileDidLoaded) {
|
||||
String location = (String)args[0];
|
||||
if (currentFileName != null && currentFileName.equals(location)) {
|
||||
progressBar.setVisibility(View.GONE);
|
||||
updateActionOverlays();
|
||||
for (int a = 0; a < 3; a++) {
|
||||
if (currentFileNames[a] != null && currentFileNames[a].equals(location)) {
|
||||
checkProgress(a);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (id == NotificationCenter.FileLoadProgressChanged) {
|
||||
String location = (String)args[0];
|
||||
if (currentFileName != null && currentFileName.equals(location)) {
|
||||
Float progress = (Float)args[1];
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
if (android.os.Build.VERSION.SDK_INT >= 11) {
|
||||
progressBar.setProgress((int) (progress * 100));
|
||||
AnimatorSet animatorSet = new AnimatorSet();
|
||||
animatorSet.playTogether(
|
||||
ObjectAnimator.ofInt(progressBar, "progress", (int) (progress * 100))
|
||||
);
|
||||
animatorSet.setDuration(400);
|
||||
animatorSet.start();
|
||||
} else {
|
||||
progressBar.setProgress((int) (progress * 100));
|
||||
for (int a = 0; a < 3; a++) {
|
||||
if (currentFileNames[a] != null && currentFileNames[a].equals(location)) {
|
||||
Float progress = (Float) args[1];
|
||||
radialProgressViews[a].setProgress(progress, true);
|
||||
}
|
||||
}
|
||||
} else if (id == NotificationCenter.userPhotosLoaded) {
|
||||
@ -370,7 +433,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
|
||||
setImageIndex(0, true);
|
||||
}
|
||||
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) {
|
||||
@ -471,10 +534,10 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
|
||||
|
||||
if (progressDrawables == null) {
|
||||
progressDrawables = new Drawable[4];
|
||||
progressDrawables[0] = parentActivity.getDrawable(R.drawable.cancel_big);
|
||||
progressDrawables[1] = parentActivity.getDrawable(R.drawable.circle_big);
|
||||
progressDrawables[2] = parentActivity.getDrawable(R.drawable.load_big);
|
||||
progressDrawables[3] = parentActivity.getDrawable(R.drawable.play_big);
|
||||
progressDrawables[0] = parentActivity.getResources().getDrawable(R.drawable.circle_big);
|
||||
progressDrawables[1] = parentActivity.getResources().getDrawable(R.drawable.cancel_big);
|
||||
progressDrawables[2] = parentActivity.getResources().getDrawable(R.drawable.load_big);
|
||||
progressDrawables[3] = parentActivity.getResources().getDrawable(R.drawable.play_big);
|
||||
}
|
||||
|
||||
scroller = new Scroller(activity);
|
||||
@ -529,7 +592,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
|
||||
}
|
||||
|
||||
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) {
|
||||
if (opennedFromMedia) {
|
||||
@ -607,6 +670,13 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
|
||||
bottomLayout.setLayoutParams(layoutParams);
|
||||
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.setImageResource(R.drawable.ic_ab_share_white);
|
||||
shareButton.setScaleType(ImageView.ScaleType.CENTER);
|
||||
@ -797,20 +867,6 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
|
||||
doneButtonTextView.setText(LocaleController.getString("Send", R.string.Send).toUpperCase());
|
||||
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.setOnDoubleTapListener(this);
|
||||
|
||||
@ -818,10 +874,6 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
|
||||
leftImage.setParentView(containerView);
|
||||
rightImage.setParentView(containerView);
|
||||
|
||||
currentOverlay = new OverlayView(containerView.getContext());
|
||||
containerView.addView(currentOverlay);
|
||||
currentOverlay.setVisibility(View.GONE);
|
||||
|
||||
checkImageView = new ImageView(containerView.getContext());
|
||||
containerView.addView(checkImageView);
|
||||
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) {
|
||||
if (show) {
|
||||
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) {
|
||||
return null;
|
||||
}
|
||||
TLRPC.InputFileLocation file = fileLocation != null ? fileLocation : getInputFileLocation(index);
|
||||
TLRPC.InputFileLocation file = getInputFileLocation(index);
|
||||
if (file == 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) {
|
||||
classGuid = ConnectionsManager.getInstance().generateClassGuid();
|
||||
currentMessageObject = null;
|
||||
currentFileLocation = null;
|
||||
currentPathObject = null;
|
||||
currentIndex = -1;
|
||||
currentFileName = null;
|
||||
currentFileNames[0] = null;
|
||||
currentFileNames[1] = null;
|
||||
currentFileNames[2] = null;
|
||||
avatarsUserId = 0;
|
||||
currentDialogId = 0;
|
||||
totalImagesCount = 0;
|
||||
@ -1157,6 +1146,11 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
|
||||
bottomLayout.setVisibility(View.VISIBLE);
|
||||
checkImageView.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) {
|
||||
imagesArr.add(messageObject);
|
||||
@ -1180,13 +1174,6 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
|
||||
} else {
|
||||
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);
|
||||
} else if (fileLocation != null) {
|
||||
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;
|
||||
setImageIndex(index, true);
|
||||
} else if (photos != null) {
|
||||
@ -1247,7 +1227,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
|
||||
if (currentDialogId != 0 && totalImagesCount == 0) {
|
||||
MessagesController.getInstance().getMediaCount(currentDialogId, classGuid, true);
|
||||
} 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);
|
||||
int prevIndex = currentIndex;
|
||||
currentIndex = index;
|
||||
currentFileName = getFileName(index, null);
|
||||
currentFileNames[0] = getFileName(index);
|
||||
currentFileNames[1] = getFileName(index + 1);
|
||||
currentFileNames[2] = getFileName(index - 1);
|
||||
boolean sameImage = false;
|
||||
|
||||
if (!imagesArr.isEmpty()) {
|
||||
@ -1273,7 +1255,11 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
|
||||
} else {
|
||||
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 (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));
|
||||
}
|
||||
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()) {
|
||||
nameTextView.setText("");
|
||||
dateTextView.setText("");
|
||||
@ -1297,6 +1290,8 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
|
||||
sameImage = true;
|
||||
}
|
||||
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()) {
|
||||
currentPathObject = imagesArrLocals.get(index).path;
|
||||
actionBarLayer.setTitle(LocaleController.formatString("Of", R.string.Of, currentIndex + 1, imagesArrLocals.size()));
|
||||
@ -1351,7 +1346,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
|
||||
canDragDown = true;
|
||||
changingPage = false;
|
||||
switchImageAfterAnimation = 0;
|
||||
canZoom = currentFileName == null || !currentFileName.endsWith("mp4");
|
||||
canZoom = currentFileNames[0] != null && !currentFileNames[0].endsWith("mp4") && radialProgressViews[0].backgroundState != 0;
|
||||
updateMinMax(scale);
|
||||
}
|
||||
|
||||
@ -1366,45 +1361,66 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
|
||||
centerImage = leftImage;
|
||||
leftImage = temp;
|
||||
setIndexToImage(leftImage, currentIndex - 1);
|
||||
radialProgressViews[0].setRadOffset(radialProgressViews[2].getRadOffset());
|
||||
} else if (prevIndex < currentIndex) {
|
||||
ImageReceiver temp = leftImage;
|
||||
leftImage = centerImage;
|
||||
centerImage = rightImage;
|
||||
rightImage = temp;
|
||||
radialProgressViews[0].setRadOffset(radialProgressViews[1].getRadOffset());
|
||||
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;
|
||||
if (currentMessageObject != null) {
|
||||
f = FileLoader.getPathToMessage(currentMessageObject.messageOwner);
|
||||
MessageObject messageObject = imagesArr.get(index);
|
||||
f = FileLoader.getPathToMessage(messageObject.messageOwner);
|
||||
} 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()) {
|
||||
progressBar.setVisibility(View.GONE);
|
||||
if (f != null && f.exists()) {
|
||||
if (currentFileNames[a].endsWith("mp4")) {
|
||||
radialProgressViews[a].setBackgroundState(3);
|
||||
} else {
|
||||
radialProgressViews[a].setBackgroundState(-1);
|
||||
}
|
||||
} else {
|
||||
if (currentFileName.endsWith("mp4")) {
|
||||
if (!FileLoader.getInstance().isLoadingFile(currentFileName)) {
|
||||
progressBar.setVisibility(View.GONE);
|
||||
if (currentFileNames[a].endsWith("mp4")) {
|
||||
if (!FileLoader.getInstance().isLoadingFile(currentFileNames[a])) {
|
||||
radialProgressViews[a].setBackgroundState(2);
|
||||
} else {
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
radialProgressViews[a].setBackgroundState(1);
|
||||
}
|
||||
} else {
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
radialProgressViews[a].setBackgroundState(0);
|
||||
}
|
||||
Float progress = FileLoader.getInstance().getFileProgress(currentFileName);
|
||||
if (progress != null) {
|
||||
progressBar.setProgress((int)(progress * 100));
|
||||
} else {
|
||||
progressBar.setProgress(0);
|
||||
Float progress = FileLoader.getInstance().getFileProgress(currentFileNames[a]);
|
||||
if (progress == null) {
|
||||
progress = 0.0f;
|
||||
}
|
||||
radialProgressViews[a].setProgress(progress, false);
|
||||
}
|
||||
if (a == 0) {
|
||||
canZoom = currentFileNames[0] != null && !currentFileNames[0].endsWith("mp4") && radialProgressViews[0].backgroundState != 0;
|
||||
}
|
||||
} else {
|
||||
progressBar.setVisibility(View.GONE);
|
||||
radialProgressViews[a].setBackgroundState(-1);
|
||||
}
|
||||
updateActionOverlays();
|
||||
}
|
||||
|
||||
private void setIndexToImage(ImageReceiver imageReceiver, int index) {
|
||||
@ -1546,7 +1562,6 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
|
||||
isVisible = true;
|
||||
backgroundDrawable.setAlpha(255);
|
||||
toggleActionBar(true, false);
|
||||
overlayViewVisible = true;
|
||||
|
||||
if(android.os.Build.VERSION.SDK_INT >= 11) {
|
||||
AndroidUtilities.lockOrientation(parentActivity);
|
||||
@ -1606,8 +1621,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
|
||||
ObjectAnimator.ofInt(animatingImageView, "clipHorizontal", clipHorizontal, 0),
|
||||
ObjectAnimator.ofInt(animatingImageView, "clipTop", clipTop, 0),
|
||||
ObjectAnimator.ofInt(animatingImageView, "clipBottom", clipBottom, 0),
|
||||
ObjectAnimator.ofFloat(containerView, "alpha", 0.0f, 1.0f),
|
||||
ObjectAnimator.ofFloat(currentOverlay, "alpha", 1.0f)
|
||||
ObjectAnimator.ofFloat(containerView, "alpha", 0.0f, 1.0f)
|
||||
);
|
||||
|
||||
animationEndRunnable = new Runnable() {
|
||||
@ -1871,6 +1885,11 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
|
||||
currentFileLocation = null;
|
||||
currentPathObject = null;
|
||||
currentThumb = null;
|
||||
for (int a = 0; a < 3; a++) {
|
||||
if (radialProgressViews[a] != null) {
|
||||
radialProgressViews[a].setBackgroundState(-1);
|
||||
}
|
||||
}
|
||||
centerImage.setImageBitmap((Bitmap)null);
|
||||
leftImage.setImageBitmap((Bitmap)null);
|
||||
rightImage.setImageBitmap((Bitmap)null);
|
||||
@ -1987,7 +2006,6 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
|
||||
} else if (draggingDown) {
|
||||
translationY = ev.getY() - dragY;
|
||||
containerView.invalidate();
|
||||
toggleOverlayView(false);
|
||||
} else if (!invalidCoords && animationStartTime == 0) {
|
||||
float moveDx = moveStartX - ev.getX();
|
||||
float moveDy = moveStartY - ev.getY();
|
||||
@ -1999,8 +2017,6 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
|
||||
canDragDown = false;
|
||||
}
|
||||
|
||||
toggleOverlayView(false);
|
||||
|
||||
moveStartX = ev.getX();
|
||||
moveStartY = ev.getY();
|
||||
updateMinMax(scale);
|
||||
@ -2145,9 +2161,6 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
|
||||
}
|
||||
|
||||
private void animateTo(float newScale, float newTx, float newTy, boolean isZoom) {
|
||||
if (switchImageAfterAnimation == 0) {
|
||||
toggleOverlayView(true);
|
||||
}
|
||||
if (scale == newScale && translationX == newTx && translationY == newTy) {
|
||||
AndroidUtilities.unlockOrientation(parentActivity);
|
||||
return;
|
||||
@ -2227,7 +2240,6 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
|
||||
setImageIndex(currentIndex - 1, false);
|
||||
}
|
||||
switchImageAfterAnimation = 0;
|
||||
toggleOverlayView(true);
|
||||
}
|
||||
|
||||
canvas.translate(translationX, translationY);
|
||||
@ -2261,8 +2273,8 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
|
||||
centerImage.draw(canvas);
|
||||
}
|
||||
|
||||
ImageReceiver sideImage = null;
|
||||
if (scale >= 1.0f) {
|
||||
ImageReceiver sideImage = null;
|
||||
float k = 1;
|
||||
if (currentTranslationX > maxX + AndroidUtilities.dp(20)) {
|
||||
k = -1;
|
||||
@ -2297,6 +2309,21 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
|
||||
}
|
||||
|
||||
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")
|
||||
@ -2328,8 +2355,8 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
|
||||
}
|
||||
}
|
||||
|
||||
private void onActionClick(View view) {
|
||||
if (currentMessageObject == null || currentFileName == null) {
|
||||
private void onActionClick() {
|
||||
if (currentMessageObject == null || currentFileNames[0] == null) {
|
||||
return;
|
||||
}
|
||||
boolean loadFile = false;
|
||||
@ -2353,12 +2380,11 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
|
||||
}
|
||||
}
|
||||
if (loadFile) {
|
||||
if (!FileLoader.getInstance().isLoadingFile(currentFileName)) {
|
||||
if (!FileLoader.getInstance().isLoadingFile(currentFileNames[0])) {
|
||||
FileLoader.getInstance().loadFile(currentMessageObject.messageOwner.media.video, true);
|
||||
} else {
|
||||
FileLoader.getInstance().cancelLoadFile(currentMessageObject.messageOwner.media.video);
|
||||
}
|
||||
updateActionOverlays();
|
||||
}
|
||||
}
|
||||
|
||||
@ -2400,6 +2426,19 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat
|
||||
@Override
|
||||
public boolean onSingleTapConfirmed(MotionEvent e) {
|
||||
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);
|
||||
} else {
|
||||
checkImageView.performClick();
|
||||
|
Loading…
Reference in New Issue
Block a user