Bug fixes

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

View File

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

View File

@ -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

View File

@ -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);
@ -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.

View File

@ -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;
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;
}
AndroidUtilities.RunOnUIThread(new Runnable() {
@Override
public void run() {
if (exist != null) {
putEncryptedChat(newChat, false);
}
MessagesStorage.getInstance().updateEncryptedChat(newChat);
@ -3556,67 +3561,13 @@ public class MessagesController implements NotificationCenter.NotificationCenter
}
}
public TLRPC.Message decryptMessage(TLRPC.EncryptedMessage message) {
final TLRPC.EncryptedChat chat = getEncryptedChatDB(message.chat_id);
if (chat == null || chat instanceof TLRPC.TL_encryptedChatDiscarded) {
return null;
}
ByteBufferDesc is = BuffersStorage.getInstance().getFreeBuffer(message.bytes.length);
is.writeRaw(message.bytes);
is.position(0);
long fingerprint = is.readInt64();
if (chat.key_fingerprint == fingerprint) {
byte[] messageKey = is.readData(16);
MessageKeyData keyData = Utilities.generateMessageKeyData(chat.auth_key, messageKey, false);
Utilities.aesIgeEncryption(is.buffer, keyData.aesKey, keyData.aesIv, false, false, 24, is.limit() - 24);
int len = is.readInt32();
TLObject object = TLClassStore.Instance().TLdeserialize(is, is.readInt32());
BuffersStorage.getInstance().reuseFreeBuffer(is);
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_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) {
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;
MessagesStorage.getInstance().updateEncryptedChat(newChat);
AndroidUtilities.RunOnUIThread(new Runnable() {
@Override
public void run() {
putEncryptedChat(newChat, false);
NotificationCenter.getInstance().postNotificationName(NotificationCenter.encryptedChatUpdated, newChat);
}
});
declineSecretChat(chat.id);
}
});
return null;
}
chat.seq_in = layer.out_seq_no;
MessagesStorage.getInstance().updateEncryptedChatSeq(chat);
object = layer.message;
}
if (object instanceof TLRPC.TL_decryptedMessage) {
TLRPC.TL_decryptedMessage decryptedMessage = (TLRPC.TL_decryptedMessage)object;
TLRPC.TL_message newMessage = null;
@ -3628,12 +3579,12 @@ public class MessagesController implements NotificationCenter.NotificationCenter
newMessage.ttl = chat.ttl;
}
newMessage.message = decryptedMessage.message;
newMessage.date = message.date;
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 = message.random_id;
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;
@ -3674,14 +3625,14 @@ public class MessagesController implements NotificationCenter.NotificationCenter
big.w = decryptedMessage.media.w;
big.h = decryptedMessage.media.h;
big.type = "x";
big.size = message.file.size;
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 = 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;
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) {
@ -3701,15 +3652,15 @@ public class MessagesController implements NotificationCenter.NotificationCenter
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.dc_id = 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.date = 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.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;
@ -3725,13 +3676,13 @@ public class MessagesController implements NotificationCenter.NotificationCenter
}
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.id = file.id;
newMessage.media.document.access_hash = file.access_hash;
newMessage.media.document.user_id = decryptedMessage.media.user_id;
newMessage.media.document.date = message.date;
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 = message.file.size;
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) {
@ -3745,21 +3696,21 @@ public class MessagesController implements NotificationCenter.NotificationCenter
newMessage.media.document.thumb = new TLRPC.TL_photoSizeEmpty();
newMessage.media.document.thumb.type = "s";
}
newMessage.media.document.dc_id = message.file.dc_id;
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 = message.file.id;
newMessage.media.audio.access_hash = message.file.access_hash;
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 = message.date;
newMessage.media.audio.size = message.file.size;
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 = message.file.dc_id;
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) {
@ -3791,7 +3742,7 @@ public class MessagesController implements NotificationCenter.NotificationCenter
newMessage.local_id = newMessage.id = UserConfig.getNewMessageId();
UserConfig.saveConfig(false);
newMessage.flags = TLRPC.MESSAGE_FLAG_UNREAD;
newMessage.date = message.date;
newMessage.date = date;
newMessage.from_id = from_id;
newMessage.to_id = new TLRPC.TL_peerUser();
newMessage.to_id.user_id = UserConfig.getClientUserId();
@ -3837,9 +3788,6 @@ public class MessagesController implements NotificationCenter.NotificationCenter
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);
@ -3847,8 +3795,6 @@ public class MessagesController implements NotificationCenter.NotificationCenter
if (currentPeerLayer < 17) {
SendMessagesHelper.getInstance().sendNotifyLayerMessage(chat, null);
}
}
});
} else if (serviceMessage.action instanceof TLRPC.TL_decryptedMessageActionResend) {
} else {
@ -3860,6 +3806,129 @@ public class MessagesController implements NotificationCenter.NotificationCenter
} 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) {
return null;
}
ByteBufferDesc is = BuffersStorage.getInstance().getFreeBuffer(message.bytes.length);
is.writeRaw(message.bytes);
is.position(0);
long fingerprint = is.readInt64();
if (chat.key_fingerprint == fingerprint) {
byte[] messageKey = is.readData(16);
MessageKeyData keyData = Utilities.generateMessageKeyData(chat.auth_key, messageKey, false);
Utilities.aesIgeEncryption(is.buffer, keyData.aesKey, keyData.aesIv, false, false, 24, is.limit() - 24);
int len = is.readInt32();
TLObject object = TLClassStore.Instance().TLdeserialize(is, is.readInt32());
BuffersStorage.getInstance().reuseFreeBuffer(is);
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 (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() {
putEncryptedChat(newChat, false);
MessagesStorage.getInstance().updateEncryptedChat(newChat);
NotificationCenter.getInstance().postNotificationName(NotificationCenter.encryptedChatUpdated, newChat);
}
});
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);
}
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;
}
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");

View File

@ -110,6 +110,7 @@ public class MessagesStorage {
database.executeFast("CREATE TABLE download_queue(uid INTEGER, type INTEGER, date INTEGER, data BLOB, PRIMARY KEY (uid, type));").stepThis().dispose();
database.executeFast("CREATE TABLE 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

View File

@ -1177,6 +1177,9 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
if (req == null || chat.auth_key == null || chat instanceof TLRPC.TL_encryptedChatRequested || chat instanceof TLRPC.TL_encryptedChatWaiting) {
return;
}
Utilities.stageQueue.postRunnable(new Runnable() {
@Override
public void run() {
TLObject toEncryptObject = null;
if (AndroidUtilities.getPeerLayerVersion(chat.layer) >= 17) {
TLRPC.TL_decryptedMessageLayer layer = new TLRPC.TL_decryptedMessageLayer();
@ -1280,16 +1283,11 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
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() {
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) {
@ -1343,6 +1341,8 @@ public class SendMessagesHelper implements NotificationCenter.NotificationCenter
}
});
}
});
}
private void processSentMessage(TLRPC.Message newMsg, TLRPC.Message sentMessage, TLRPC.EncryptedFile file, TLRPC.DecryptedMessage decryptedMessage, String originalPath) {
if (sentMessage != null) {

View File

@ -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 {

View File

@ -371,6 +371,7 @@ public class TLClassStore {
classStore.put(TLRPC.TL_userForeign_old.constructor, TLRPC.TL_userForeign_old.class);
classStore.put(TLRPC.TL_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;

View File

@ -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;

View File

@ -1685,10 +1685,12 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
maxMessageId = Math.max(obj.messageOwner.id, maxMessageId);
minMessageId = Math.min(obj.messageOwner.id, minMessageId);
}
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) {
continue;

View File

@ -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);

View File

@ -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)) {
for (int a = 0; a < 3; a++) {
if (currentFileNames[a] != null && currentFileNames[a].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));
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("");
}
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 {
if (currentFileName.endsWith("mp4")) {
if (!FileLoader.getInstance().isLoadingFile(currentFileName)) {
progressBar.setVisibility(View.GONE);
} else {
progressBar.setVisibility(View.VISIBLE);
radialProgressViews[a].setBackgroundState(-1);
}
} else {
progressBar.setVisibility(View.VISIBLE);
}
Float progress = FileLoader.getInstance().getFileProgress(currentFileName);
if (progress != null) {
progressBar.setProgress((int)(progress * 100));
if (currentFileNames[a].endsWith("mp4")) {
if (!FileLoader.getInstance().isLoadingFile(currentFileNames[a])) {
radialProgressViews[a].setBackgroundState(2);
} else {
progressBar.setProgress(0);
}
radialProgressViews[a].setBackgroundState(1);
}
} else {
progressBar.setVisibility(View.GONE);
radialProgressViews[a].setBackgroundState(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 {
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);
}
if (scale >= 1.0f) {
ImageReceiver sideImage = null;
if (scale >= 1.0f) {
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();