Merge branch 'dev'
This commit is contained in:
commit
8c50d4d03b
@ -3,7 +3,7 @@ buildscript {
|
|||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:0.13.+'
|
classpath 'com.android.tools.build:gradle:0.14.0'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
apply plugin: 'com.android.application'
|
apply plugin: 'com.android.application'
|
||||||
@ -17,7 +17,7 @@ tasks.withType(JavaCompile) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile 'com.android.support:support-v4:20.0.+'
|
compile 'com.android.support:support-v4:21.0.+'
|
||||||
compile 'com.google.android.gms:play-services:3.2.+'
|
compile 'com.google.android.gms:play-services:3.2.+'
|
||||||
compile 'net.hockeyapp.android:HockeySDK:3.0.2'
|
compile 'net.hockeyapp.android:HockeySDK:3.0.2'
|
||||||
compile 'com.googlecode.mp4parser:isoparser:1.0.+'
|
compile 'com.googlecode.mp4parser:isoparser:1.0.+'
|
||||||
@ -25,7 +25,7 @@ dependencies {
|
|||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 21
|
compileSdkVersion 21
|
||||||
buildToolsVersion '21.0.2'
|
buildToolsVersion '21.1.1'
|
||||||
|
|
||||||
signingConfigs {
|
signingConfigs {
|
||||||
debug {
|
debug {
|
||||||
@ -43,19 +43,19 @@ android {
|
|||||||
buildTypes {
|
buildTypes {
|
||||||
debug {
|
debug {
|
||||||
debuggable true
|
debuggable true
|
||||||
jniDebugBuild false
|
jniDebuggable true
|
||||||
signingConfig signingConfigs.debug
|
signingConfig signingConfigs.debug
|
||||||
}
|
}
|
||||||
|
|
||||||
release {
|
release {
|
||||||
debuggable false
|
debuggable false
|
||||||
jniDebugBuild false
|
jniDebuggable false
|
||||||
signingConfig signingConfigs.release
|
signingConfig signingConfigs.release
|
||||||
}
|
}
|
||||||
|
|
||||||
foss {
|
foss {
|
||||||
debuggable false
|
debuggable false
|
||||||
jniDebugBuild false
|
jniDebuggable false
|
||||||
signingConfig signingConfigs.release
|
signingConfig signingConfigs.release
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -65,22 +65,22 @@ android {
|
|||||||
jni.srcDirs = [] //disable automatic ndk-build call
|
jni.srcDirs = [] //disable automatic ndk-build call
|
||||||
}
|
}
|
||||||
|
|
||||||
sourceSets {
|
sourceSets.debug {
|
||||||
debug {
|
manifest.srcFile 'config/debug/AndroidManifest.xml'
|
||||||
manifest.srcFile 'config/debug/AndroidManifest.xml'
|
}
|
||||||
}
|
|
||||||
release {
|
sourceSets.release {
|
||||||
manifest.srcFile 'config/release/AndroidManifest.xml'
|
manifest.srcFile 'config/release/AndroidManifest.xml'
|
||||||
}
|
}
|
||||||
foss {
|
|
||||||
manifest.srcFile 'config/foss/AndroidManifest.xml'
|
sourceSets.foss {
|
||||||
}
|
manifest.srcFile 'config/foss/AndroidManifest.xml'
|
||||||
}
|
}
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion 8
|
minSdkVersion 8
|
||||||
targetSdkVersion 19
|
targetSdkVersion 21
|
||||||
versionCode 374
|
versionCode 403
|
||||||
versionName "1.9.6"
|
versionName "2.1.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
android:icon="@drawable/ic_launcher"
|
android:icon="@drawable/ic_launcher"
|
||||||
android:label="@string/AppName"
|
android:label="@string/AppName"
|
||||||
android:theme="@style/Theme.TMessages.Start"
|
android:theme="@style/Theme.TMessages.Start"
|
||||||
android:name="org.telegram.ui.ApplicationLoader"
|
android:name=".ApplicationLoader"
|
||||||
android:hardwareAccelerated="true"
|
android:hardwareAccelerated="true"
|
||||||
android:largeHeap="true">
|
android:largeHeap="true">
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
android:icon="@drawable/ic_launcher"
|
android:icon="@drawable/ic_launcher"
|
||||||
android:label="@string/AppName"
|
android:label="@string/AppName"
|
||||||
android:theme="@style/Theme.TMessages.Start"
|
android:theme="@style/Theme.TMessages.Start"
|
||||||
android:name="org.telegram.ui.ApplicationLoader"
|
android:name=".ApplicationLoader"
|
||||||
android:hardwareAccelerated="true"
|
android:hardwareAccelerated="true"
|
||||||
android:largeHeap="true">
|
android:largeHeap="true">
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
android:icon="@drawable/ic_launcher"
|
android:icon="@drawable/ic_launcher"
|
||||||
android:label="@string/AppName"
|
android:label="@string/AppName"
|
||||||
android:theme="@style/Theme.TMessages.Start"
|
android:theme="@style/Theme.TMessages.Start"
|
||||||
android:name="org.telegram.ui.ApplicationLoader"
|
android:name=".ApplicationLoader"
|
||||||
android:hardwareAccelerated="true"
|
android:hardwareAccelerated="true"
|
||||||
android:largeHeap="true">
|
android:largeHeap="true">
|
||||||
|
|
||||||
|
@ -2,10 +2,10 @@ LOCAL_PATH := $(call my-dir)
|
|||||||
|
|
||||||
include $(CLEAR_VARS)
|
include $(CLEAR_VARS)
|
||||||
LOCAL_PRELINK_MODULE := false
|
LOCAL_PRELINK_MODULE := false
|
||||||
LOCAL_MODULE := tmessages
|
LOCAL_MODULE := tmessages.4
|
||||||
LOCAL_CFLAGS := -w -std=gnu99 -O2 -DNULL=0 -DSOCKLEN_T=socklen_t -DLOCALE_NOT_USED -D_LARGEFILE_SOURCE=1 -D_FILE_OFFSET_BITS=64
|
LOCAL_CFLAGS := -w -std=gnu99 -O2 -DNULL=0 -DSOCKLEN_T=socklen_t -DLOCALE_NOT_USED -D_LARGEFILE_SOURCE=1 -D_FILE_OFFSET_BITS=64
|
||||||
LOCAL_CFLAGS += -Drestrict='' -D__EMX__ -DOPUS_BUILD -DFIXED_POINT -DUSE_ALLOCA -DHAVE_LRINT -DHAVE_LRINTF -fno-math-errno
|
LOCAL_CFLAGS += -Drestrict='' -D__EMX__ -DOPUS_BUILD -DFIXED_POINT -DUSE_ALLOCA -DHAVE_LRINT -DHAVE_LRINTF -fno-math-errno
|
||||||
LOCAL_CFLAGS += -DANDROID_NDK -DDISABLE_IMPORTGL -fno-strict-aliasing -fprefetch-loop-arrays -DAVOID_TABLES -DANDROID_TILE_BASED_DECODE -DANDROID_ARMV6_IDCT
|
LOCAL_CFLAGS += -DANDROID_NDK -DDISABLE_IMPORTGL -fno-strict-aliasing -fprefetch-loop-arrays -DAVOID_TABLES -DANDROID_TILE_BASED_DECODE -DANDROID_ARMV6_IDCT -DHAVE_STRCHRNUL=0
|
||||||
LOCAL_CPPFLAGS := -DBSD=1 -ffast-math -O2 -funroll-loops
|
LOCAL_CPPFLAGS := -DBSD=1 -ffast-math -O2 -funroll-loops
|
||||||
#LOCAL_LDLIBS := -llog
|
#LOCAL_LDLIBS := -llog
|
||||||
LOCAL_LDLIBS := -ljnigraphics -llog
|
LOCAL_LDLIBS := -ljnigraphics -llog
|
||||||
@ -162,10 +162,23 @@ LOCAL_SRC_FILES += \
|
|||||||
./giflib/gifalloc.c
|
./giflib/gifalloc.c
|
||||||
|
|
||||||
LOCAL_SRC_FILES += \
|
LOCAL_SRC_FILES += \
|
||||||
./aes/aes_core.c \
|
|
||||||
./aes/aes_ige.c \
|
./aes/aes_ige.c \
|
||||||
./aes/aes_misc.c
|
./aes/aes_misc.c
|
||||||
|
|
||||||
|
ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
|
||||||
|
LOCAL_SRC_FILES += ./aes/aes_arm.S
|
||||||
|
else
|
||||||
|
ifeq ($(TARGET_ARCH_ABI),armeabi)
|
||||||
|
LOCAL_SRC_FILES += ./aes/aes_arm.S
|
||||||
|
else
|
||||||
|
ifeq ($(TARGET_ARCH_ABI),x86)
|
||||||
|
LOCAL_SRC_FILES += ./aes/aes_core.c
|
||||||
|
else
|
||||||
|
LOCAL_SRC_FILES += ./aes/aes_core.c
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
LOCAL_SRC_FILES += \
|
LOCAL_SRC_FILES += \
|
||||||
./sqlite/sqlite3.c
|
./sqlite/sqlite3.c
|
||||||
|
|
||||||
@ -277,7 +290,6 @@ LOCAL_SRC_FILES += \
|
|||||||
./gif.c \
|
./gif.c \
|
||||||
./utils.c \
|
./utils.c \
|
||||||
./image.c \
|
./image.c \
|
||||||
./video.c \
|
./video.c
|
||||||
./fake.c
|
|
||||||
|
|
||||||
include $(BUILD_SHARED_LIBRARY)
|
include $(BUILD_SHARED_LIBRARY)
|
1071
TMessagesProj/jni/aes/aes_arm.S
Normal file
1071
TMessagesProj/jni/aes/aes_arm.S
Normal file
File diff suppressed because it is too large
Load Diff
51
TMessagesProj/jni/aes/arm_arch.h
Normal file
51
TMessagesProj/jni/aes/arm_arch.h
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
#ifndef __ARM_ARCH_H__
|
||||||
|
#define __ARM_ARCH_H__
|
||||||
|
|
||||||
|
#if !defined(__ARM_ARCH__)
|
||||||
|
# if defined(__CC_ARM)
|
||||||
|
# define __ARM_ARCH__ __TARGET_ARCH_ARM
|
||||||
|
# if defined(__BIG_ENDIAN)
|
||||||
|
# define __ARMEB__
|
||||||
|
# else
|
||||||
|
# define __ARMEL__
|
||||||
|
# endif
|
||||||
|
# elif defined(__GNUC__)
|
||||||
|
/*
|
||||||
|
* Why doesn't gcc define __ARM_ARCH__? Instead it defines
|
||||||
|
* bunch of below macros. See all_architectires[] table in
|
||||||
|
* gcc/config/arm/arm.c. On a side note it defines
|
||||||
|
* __ARMEL__/__ARMEB__ for little-/big-endian.
|
||||||
|
*/
|
||||||
|
# if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || \
|
||||||
|
defined(__ARM_ARCH_7R__)|| defined(__ARM_ARCH_7M__) || \
|
||||||
|
defined(__ARM_ARCH_7EM__)
|
||||||
|
# define __ARM_ARCH__ 7
|
||||||
|
# elif defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || \
|
||||||
|
defined(__ARM_ARCH_6K__)|| defined(__ARM_ARCH_6M__) || \
|
||||||
|
defined(__ARM_ARCH_6Z__)|| defined(__ARM_ARCH_6ZK__) || \
|
||||||
|
defined(__ARM_ARCH_6T2__)
|
||||||
|
# define __ARM_ARCH__ 6
|
||||||
|
# elif defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5T__) || \
|
||||||
|
defined(__ARM_ARCH_5E__)|| defined(__ARM_ARCH_5TE__) || \
|
||||||
|
defined(__ARM_ARCH_5TEJ__)
|
||||||
|
# define __ARM_ARCH__ 5
|
||||||
|
# elif defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__)
|
||||||
|
# define __ARM_ARCH__ 4
|
||||||
|
# else
|
||||||
|
# error "unsupported ARM architecture"
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef OPENSSL_FIPSCANISTER
|
||||||
|
#include <openssl/fipssyms.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !__ASSEMBLER__
|
||||||
|
extern unsigned int OPENSSL_armcap_P;
|
||||||
|
|
||||||
|
#define ARMV7_NEON (1<<0)
|
||||||
|
#define ARMV7_TICK (1<<1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
@ -1,6 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
void fakeFunction() {
|
|
||||||
printf("some androids has buggy native loader, so i should check size of libs in java to know that native library is correct. So each changed native library should has diffrent size in different app versions. This function will increase lib size for few bytes :)");
|
|
||||||
printf("");
|
|
||||||
}
|
|
@ -589,7 +589,7 @@ static jint open(GifFileType *GifFileIn, int Error, int startPos, JNIEnv *env, j
|
|||||||
return (jint)(Error == 0 ? info : NULL);
|
return (jint)(Error == 0 ? info : NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jlong JNICALL Java_org_telegram_ui_Views_GifDrawable_getAllocationByteCount(JNIEnv *env, jclass class, jobject gifInfo) {
|
JNIEXPORT jlong JNICALL Java_org_telegram_ui_Components_GifDrawable_getAllocationByteCount(JNIEnv *env, jclass class, jobject gifInfo) {
|
||||||
GifInfo *info = (GifInfo *)gifInfo;
|
GifInfo *info = (GifInfo *)gifInfo;
|
||||||
if (info == NULL) {
|
if (info == NULL) {
|
||||||
return 0;
|
return 0;
|
||||||
@ -602,7 +602,7 @@ JNIEXPORT jlong JNICALL Java_org_telegram_ui_Views_GifDrawable_getAllocationByte
|
|||||||
return sum;
|
return sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT void JNICALL Java_org_telegram_ui_Views_GifDrawable_reset(JNIEnv *env, jclass class, jobject gifInfo) {
|
JNIEXPORT void JNICALL Java_org_telegram_ui_Components_GifDrawable_reset(JNIEnv *env, jclass class, jobject gifInfo) {
|
||||||
GifInfo *info = (GifInfo *)gifInfo;
|
GifInfo *info = (GifInfo *)gifInfo;
|
||||||
if (info == NULL) {
|
if (info == NULL) {
|
||||||
return;
|
return;
|
||||||
@ -610,7 +610,7 @@ JNIEXPORT void JNICALL Java_org_telegram_ui_Views_GifDrawable_reset(JNIEnv *env,
|
|||||||
reset(info);
|
reset(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT void JNICALL Java_org_telegram_ui_Views_GifDrawable_setSpeedFactor(JNIEnv *env, jclass class, jobject gifInfo, jfloat factor) {
|
JNIEXPORT void JNICALL Java_org_telegram_ui_Components_GifDrawable_setSpeedFactor(JNIEnv *env, jclass class, jobject gifInfo, jfloat factor) {
|
||||||
GifInfo *info = (GifInfo *)gifInfo;
|
GifInfo *info = (GifInfo *)gifInfo;
|
||||||
if (info == NULL) {
|
if (info == NULL) {
|
||||||
return;
|
return;
|
||||||
@ -618,7 +618,7 @@ JNIEXPORT void JNICALL Java_org_telegram_ui_Views_GifDrawable_setSpeedFactor(JNI
|
|||||||
info->speedFactor = factor;
|
info->speedFactor = factor;
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT void JNICALL Java_org_telegram_ui_Views_GifDrawable_seekToTime(JNIEnv *env, jclass class, jobject gifInfo, jint desiredPos, jintArray jPixels) {
|
JNIEXPORT void JNICALL Java_org_telegram_ui_Components_GifDrawable_seekToTime(JNIEnv *env, jclass class, jobject gifInfo, jint desiredPos, jintArray jPixels) {
|
||||||
GifInfo *info = (GifInfo *)gifInfo;
|
GifInfo *info = (GifInfo *)gifInfo;
|
||||||
if (info == NULL || jPixels == NULL) {
|
if (info == NULL || jPixels == NULL) {
|
||||||
return;
|
return;
|
||||||
@ -665,7 +665,7 @@ JNIEXPORT void JNICALL Java_org_telegram_ui_Views_GifDrawable_seekToTime(JNIEnv
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT void JNICALL Java_org_telegram_ui_Views_GifDrawable_seekToFrame(JNIEnv *env, jclass class, jobject gifInfo, jint desiredIdx, jintArray jPixels) {
|
JNIEXPORT void JNICALL Java_org_telegram_ui_Components_GifDrawable_seekToFrame(JNIEnv *env, jclass class, jobject gifInfo, jint desiredIdx, jintArray jPixels) {
|
||||||
GifInfo *info = (GifInfo *)gifInfo;
|
GifInfo *info = (GifInfo *)gifInfo;
|
||||||
if (info == NULL|| jPixels==NULL) {
|
if (info == NULL|| jPixels==NULL) {
|
||||||
return;
|
return;
|
||||||
@ -701,7 +701,7 @@ JNIEXPORT void JNICALL Java_org_telegram_ui_Views_GifDrawable_seekToFrame(JNIEnv
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT void JNICALL Java_org_telegram_ui_Views_GifDrawable_renderFrame(JNIEnv *env, jclass class, jintArray jPixels, jobject gifInfo, jintArray metaData) {
|
JNIEXPORT void JNICALL Java_org_telegram_ui_Components_GifDrawable_renderFrame(JNIEnv *env, jclass class, jintArray jPixels, jobject gifInfo, jintArray metaData) {
|
||||||
GifInfo *info = (GifInfo *)gifInfo;
|
GifInfo *info = (GifInfo *)gifInfo;
|
||||||
if (info == NULL || jPixels == NULL) {
|
if (info == NULL || jPixels == NULL) {
|
||||||
return;
|
return;
|
||||||
@ -752,7 +752,7 @@ JNIEXPORT void JNICALL Java_org_telegram_ui_Views_GifDrawable_renderFrame(JNIEnv
|
|||||||
(*env)->ReleaseIntArrayElements(env, metaData, rawMetaData, 0);
|
(*env)->ReleaseIntArrayElements(env, metaData, rawMetaData, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT void JNICALL Java_org_telegram_ui_Views_GifDrawable_free(JNIEnv *env, jclass class, jobject gifInfo) {
|
JNIEXPORT void JNICALL Java_org_telegram_ui_Components_GifDrawable_free(JNIEnv *env, jclass class, jobject gifInfo) {
|
||||||
if (gifInfo == NULL) {
|
if (gifInfo == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -765,7 +765,7 @@ JNIEXPORT void JNICALL Java_org_telegram_ui_Views_GifDrawable_free(JNIEnv *env,
|
|||||||
cleanUp(info);
|
cleanUp(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jstring JNICALL Java_org_telegram_ui_Views_GifDrawable_getComment(JNIEnv *env, jclass class, jobject gifInfo) {
|
JNIEXPORT jstring JNICALL Java_org_telegram_ui_Components_GifDrawable_getComment(JNIEnv *env, jclass class, jobject gifInfo) {
|
||||||
if (gifInfo == NULL) {
|
if (gifInfo == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -773,14 +773,14 @@ JNIEXPORT jstring JNICALL Java_org_telegram_ui_Views_GifDrawable_getComment(JNIE
|
|||||||
return (*env)->NewStringUTF(env, info->comment);
|
return (*env)->NewStringUTF(env, info->comment);
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL Java_org_telegram_ui_Views_GifDrawable_getLoopCount(JNIEnv *env, jclass class, jobject gifInfo) {
|
JNIEXPORT jint JNICALL Java_org_telegram_ui_Components_GifDrawable_getLoopCount(JNIEnv *env, jclass class, jobject gifInfo) {
|
||||||
if (gifInfo == NULL) {
|
if (gifInfo == NULL) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return ((GifInfo *)gifInfo)->loopCount;
|
return ((GifInfo *)gifInfo)->loopCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL Java_org_telegram_ui_Views_GifDrawable_getDuration(JNIEnv *env, jclass class, jobject gifInfo) {
|
JNIEXPORT jint JNICALL Java_org_telegram_ui_Components_GifDrawable_getDuration(JNIEnv *env, jclass class, jobject gifInfo) {
|
||||||
GifInfo *info = (GifInfo *)gifInfo;
|
GifInfo *info = (GifInfo *)gifInfo;
|
||||||
if (info == NULL) {
|
if (info == NULL) {
|
||||||
return 0;
|
return 0;
|
||||||
@ -793,7 +793,7 @@ JNIEXPORT jint JNICALL Java_org_telegram_ui_Views_GifDrawable_getDuration(JNIEnv
|
|||||||
return sum;
|
return sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL Java_org_telegram_ui_Views_GifDrawable_getCurrentPosition(JNIEnv *env, jclass class, jobject gifInfo) {
|
JNIEXPORT jint JNICALL Java_org_telegram_ui_Components_GifDrawable_getCurrentPosition(JNIEnv *env, jclass class, jobject gifInfo) {
|
||||||
GifInfo *info = (GifInfo *)gifInfo;
|
GifInfo *info = (GifInfo *)gifInfo;
|
||||||
if (info == NULL) {
|
if (info == NULL) {
|
||||||
return 0;
|
return 0;
|
||||||
@ -811,7 +811,7 @@ JNIEXPORT jint JNICALL Java_org_telegram_ui_Views_GifDrawable_getCurrentPosition
|
|||||||
return (int) (sum + remainder);
|
return (int) (sum + remainder);
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT void JNICALL Java_org_telegram_ui_Views_GifDrawable_saveRemainder(JNIEnv *env, jclass class, jobject gifInfo) {
|
JNIEXPORT void JNICALL Java_org_telegram_ui_Components_GifDrawable_saveRemainder(JNIEnv *env, jclass class, jobject gifInfo) {
|
||||||
GifInfo *info = (GifInfo *)gifInfo;
|
GifInfo *info = (GifInfo *)gifInfo;
|
||||||
if (info == NULL) {
|
if (info == NULL) {
|
||||||
return;
|
return;
|
||||||
@ -819,7 +819,7 @@ JNIEXPORT void JNICALL Java_org_telegram_ui_Views_GifDrawable_saveRemainder(JNIE
|
|||||||
info->lastFrameReaminder = getRealTime() - info->nextStartTime;
|
info->lastFrameReaminder = getRealTime() - info->nextStartTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT void JNICALL Java_org_telegram_ui_Views_GifDrawable_restoreRemainder(JNIEnv *env, jclass class, jobject gifInfo) {
|
JNIEXPORT void JNICALL Java_org_telegram_ui_Components_GifDrawable_restoreRemainder(JNIEnv *env, jclass class, jobject gifInfo) {
|
||||||
GifInfo *info = (GifInfo *)gifInfo;
|
GifInfo *info = (GifInfo *)gifInfo;
|
||||||
if (info == NULL || info->lastFrameReaminder == ULONG_MAX) {
|
if (info == NULL || info->lastFrameReaminder == ULONG_MAX) {
|
||||||
return;
|
return;
|
||||||
@ -828,7 +828,7 @@ JNIEXPORT void JNICALL Java_org_telegram_ui_Views_GifDrawable_restoreRemainder(J
|
|||||||
info->lastFrameReaminder = ULONG_MAX;
|
info->lastFrameReaminder = ULONG_MAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL Java_org_telegram_ui_Views_GifDrawable_openFile(JNIEnv *env, jclass class, jintArray metaData, jstring jfname) {
|
JNIEXPORT jint JNICALL Java_org_telegram_ui_Components_GifDrawable_openFile(JNIEnv *env, jclass class, jintArray metaData, jstring jfname) {
|
||||||
if (jfname == NULL) {
|
if (jfname == NULL) {
|
||||||
setMetaData(0, 0, 0, D_GIF_ERR_OPEN_FAILED, env, metaData);
|
setMetaData(0, 0, 0, D_GIF_ERR_OPEN_FAILED, env, metaData);
|
||||||
return (jint) NULL;
|
return (jint) NULL;
|
||||||
|
@ -229,23 +229,23 @@ JNIEXPORT void Java_org_telegram_messenger_Utilities_blurBitmap(JNIEnv *env, jcl
|
|||||||
AndroidBitmap_unlockPixels(env, bitmap);
|
AndroidBitmap_unlockPixels(env, bitmap);
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT void Java_org_telegram_messenger_Utilities_loadBitmap(JNIEnv *env, jclass class, jstring path, jintArray bitmap, int scale, int format, int width, int height) {
|
JNIEXPORT void Java_org_telegram_messenger_Utilities_loadBitmap(JNIEnv *env, jclass class, jstring path, jobject bitmap, int scale, int width, int height, int stride) {
|
||||||
|
|
||||||
|
AndroidBitmapInfo info;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
char *fileName = (*env)->GetStringUTFChars(env, path, NULL);
|
if ((i = AndroidBitmap_getInfo(env, bitmap, &info)) >= 0) {
|
||||||
FILE *infile;
|
char *fileName = (*env)->GetStringUTFChars(env, path, NULL);
|
||||||
|
FILE *infile;
|
||||||
if ((infile = fopen(fileName, "rb"))) {
|
|
||||||
struct my_error_mgr jerr;
|
|
||||||
struct jpeg_decompress_struct cinfo;
|
|
||||||
|
|
||||||
cinfo.err = jpeg_std_error(&jerr.pub);
|
if ((infile = fopen(fileName, "rb"))) {
|
||||||
jerr.pub.error_exit = my_error_exit;
|
struct my_error_mgr jerr;
|
||||||
|
struct jpeg_decompress_struct cinfo;
|
||||||
if (!setjmp(jerr.setjmp_buffer)) {
|
|
||||||
unsigned char *bitmapBuf = (*env)->GetPrimitiveArrayCritical(env, bitmap, 0);
|
cinfo.err = jpeg_std_error(&jerr.pub);
|
||||||
if (bitmapBuf) {
|
jerr.pub.error_exit = my_error_exit;
|
||||||
|
|
||||||
|
if (!setjmp(jerr.setjmp_buffer)) {
|
||||||
jpeg_create_decompress(&cinfo);
|
jpeg_create_decompress(&cinfo);
|
||||||
jpeg_stdio_src(&cinfo, infile);
|
jpeg_stdio_src(&cinfo, infile);
|
||||||
|
|
||||||
@ -257,60 +257,59 @@ JNIEXPORT void Java_org_telegram_messenger_Utilities_loadBitmap(JNIEnv *env, jcl
|
|||||||
jpeg_start_decompress(&cinfo);
|
jpeg_start_decompress(&cinfo);
|
||||||
int row_stride = cinfo.output_width * cinfo.output_components;
|
int row_stride = cinfo.output_width * cinfo.output_components;
|
||||||
JSAMPARRAY buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
|
JSAMPARRAY buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
|
||||||
int stride = width;
|
|
||||||
if (format == 0) {
|
|
||||||
stride *= 4;
|
|
||||||
} else if (format == 1) {
|
|
||||||
stride *= 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned char *pixels = bitmapBuf;
|
unsigned char *pixels;
|
||||||
|
if ((i = AndroidBitmap_lockPixels(env, bitmap, &pixels)) >= 0) {
|
||||||
int rowCount = min(cinfo.output_height, height);
|
int rowCount = min(cinfo.output_height, height);
|
||||||
int colCount = min(cinfo.output_width, width);
|
int colCount = min(cinfo.output_width, width);
|
||||||
|
|
||||||
while (cinfo.output_scanline < rowCount) {
|
|
||||||
jpeg_read_scanlines(&cinfo, buffer, 1);
|
|
||||||
|
|
||||||
if (format == 0) {
|
while (cinfo.output_scanline < rowCount) {
|
||||||
if (cinfo.out_color_space == JCS_GRAYSCALE) {
|
jpeg_read_scanlines(&cinfo, buffer, 1);
|
||||||
for (i = 0; i < colCount; i++) {
|
|
||||||
float alpha = buffer[0][i] / 255.0f;
|
|
||||||
pixels[i * 4] *= alpha;
|
|
||||||
pixels[i * 4 + 1] *= alpha;
|
|
||||||
pixels[i * 4 + 2] *= alpha;
|
|
||||||
pixels[i * 4 + 3] = buffer[0][i];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
int c = 0;
|
|
||||||
for (i = 0; i < colCount; i++) {
|
|
||||||
pixels[i * 4] = buffer[0][i * 3 + 2];
|
|
||||||
pixels[i * 4 + 1] = buffer[0][i * 3 + 1];
|
|
||||||
pixels[i * 4 + 2] = buffer[0][i * 3];
|
|
||||||
pixels[i * 4 + 3] = 255;
|
|
||||||
c += 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (format == 1) {
|
|
||||||
|
|
||||||
|
//if (info.format == ANDROID_BITMAP_FORMAT_RGBA_8888) {
|
||||||
|
if (cinfo.out_color_space == JCS_GRAYSCALE) {
|
||||||
|
for (i = 0; i < colCount; i++) {
|
||||||
|
float alpha = buffer[0][i] / 255.0f;
|
||||||
|
pixels[i * 4] *= alpha;
|
||||||
|
pixels[i * 4 + 1] *= alpha;
|
||||||
|
pixels[i * 4 + 2] *= alpha;
|
||||||
|
pixels[i * 4 + 3] = buffer[0][i];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
int c = 0;
|
||||||
|
for (i = 0; i < colCount; i++) {
|
||||||
|
pixels[i * 4] = buffer[0][i * 3];
|
||||||
|
pixels[i * 4 + 1] = buffer[0][i * 3 + 1];
|
||||||
|
pixels[i * 4 + 2] = buffer[0][i * 3 + 2];
|
||||||
|
pixels[i * 4 + 3] = 255;
|
||||||
|
c += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//} else if (info.format == ANDROID_BITMAP_FORMAT_RGB_565) {
|
||||||
|
|
||||||
|
//}
|
||||||
|
|
||||||
|
pixels += stride;
|
||||||
}
|
}
|
||||||
|
|
||||||
pixels += stride;
|
AndroidBitmap_unlockPixels(env, bitmap);
|
||||||
|
} else {
|
||||||
|
throwException(env, "AndroidBitmap_lockPixels() failed ! error=%d", i);
|
||||||
}
|
}
|
||||||
(*env)->ReleasePrimitiveArrayCritical(env, bitmap, bitmapBuf, 0);
|
|
||||||
jpeg_finish_decompress(&cinfo);
|
jpeg_finish_decompress(&cinfo);
|
||||||
} else {
|
} else {
|
||||||
throwException(env, "can't get bitmap buff");
|
throwException(env, "the JPEG code has signaled an error");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
jpeg_destroy_decompress(&cinfo);
|
||||||
|
fclose(infile);
|
||||||
} else {
|
} else {
|
||||||
throwException(env, "the JPEG code has signaled an error");
|
throwException(env, "can't open %s", fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
jpeg_destroy_decompress(&cinfo);
|
(*env)->ReleaseStringUTFChars(env, path, fileName);
|
||||||
fclose(infile);
|
|
||||||
} else {
|
} else {
|
||||||
throwException(env, "can't open %s", fileName);
|
throwException(env, "AndroidBitmap_getInfo() failed ! error=%d", i);
|
||||||
}
|
}
|
||||||
|
|
||||||
(*env)->ReleaseStringUTFChars(env, path, fileName);
|
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -107,9 +107,9 @@ extern "C" {
|
|||||||
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
|
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
|
||||||
** [sqlite_version()] and [sqlite_source_id()].
|
** [sqlite_version()] and [sqlite_source_id()].
|
||||||
*/
|
*/
|
||||||
#define SQLITE_VERSION "3.8.6"
|
#define SQLITE_VERSION "3.8.7.1"
|
||||||
#define SQLITE_VERSION_NUMBER 3008006
|
#define SQLITE_VERSION_NUMBER 3008007
|
||||||
#define SQLITE_SOURCE_ID "2014-08-15 11:46:33 9491ba7d738528f168657adb43a198238abde19e"
|
#define SQLITE_SOURCE_ID "2014-10-29 13:59:56 3b7b72c4685aa5cf5e675c2c47ebec10d9704221"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** CAPI3REF: Run-Time Library Version Numbers
|
** CAPI3REF: Run-Time Library Version Numbers
|
||||||
@ -497,6 +497,7 @@ SQLITE_API int sqlite3_exec(
|
|||||||
#define SQLITE_NOTICE_RECOVER_WAL (SQLITE_NOTICE | (1<<8))
|
#define SQLITE_NOTICE_RECOVER_WAL (SQLITE_NOTICE | (1<<8))
|
||||||
#define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8))
|
#define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8))
|
||||||
#define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1<<8))
|
#define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1<<8))
|
||||||
|
#define SQLITE_AUTH_USER (SQLITE_AUTH | (1<<8))
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** CAPI3REF: Flags For File Open Operations
|
** CAPI3REF: Flags For File Open Operations
|
||||||
@ -2099,7 +2100,7 @@ SQLITE_API int sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*);
|
|||||||
** turns off all busy handlers.
|
** turns off all busy handlers.
|
||||||
**
|
**
|
||||||
** ^(There can only be a single busy handler for a particular
|
** ^(There can only be a single busy handler for a particular
|
||||||
** [database connection] any any given moment. If another busy handler
|
** [database connection] at any given moment. If another busy handler
|
||||||
** was defined (using [sqlite3_busy_handler()]) prior to calling
|
** was defined (using [sqlite3_busy_handler()]) prior to calling
|
||||||
** this routine, that other busy handler is cleared.)^
|
** this routine, that other busy handler is cleared.)^
|
||||||
**
|
**
|
||||||
@ -2303,6 +2304,10 @@ SQLITE_API char *sqlite3_vsnprintf(int,char*,const char*, va_list);
|
|||||||
** sqlite3_malloc() is zero or negative then sqlite3_malloc() returns
|
** sqlite3_malloc() is zero or negative then sqlite3_malloc() returns
|
||||||
** a NULL pointer.
|
** a NULL pointer.
|
||||||
**
|
**
|
||||||
|
** ^The sqlite3_malloc64(N) routine works just like
|
||||||
|
** sqlite3_malloc(N) except that N is an unsigned 64-bit integer instead
|
||||||
|
** of a signed 32-bit integer.
|
||||||
|
**
|
||||||
** ^Calling sqlite3_free() with a pointer previously returned
|
** ^Calling sqlite3_free() with a pointer previously returned
|
||||||
** by sqlite3_malloc() or sqlite3_realloc() releases that memory so
|
** by sqlite3_malloc() or sqlite3_realloc() releases that memory so
|
||||||
** that it might be reused. ^The sqlite3_free() routine is
|
** that it might be reused. ^The sqlite3_free() routine is
|
||||||
@ -2314,24 +2319,38 @@ SQLITE_API char *sqlite3_vsnprintf(int,char*,const char*, va_list);
|
|||||||
** might result if sqlite3_free() is called with a non-NULL pointer that
|
** might result if sqlite3_free() is called with a non-NULL pointer that
|
||||||
** was not obtained from sqlite3_malloc() or sqlite3_realloc().
|
** was not obtained from sqlite3_malloc() or sqlite3_realloc().
|
||||||
**
|
**
|
||||||
** ^(The sqlite3_realloc() interface attempts to resize a
|
** ^The sqlite3_realloc(X,N) interface attempts to resize a
|
||||||
** prior memory allocation to be at least N bytes, where N is the
|
** prior memory allocation X to be at least N bytes.
|
||||||
** second parameter. The memory allocation to be resized is the first
|
** ^If the X parameter to sqlite3_realloc(X,N)
|
||||||
** parameter.)^ ^ If the first parameter to sqlite3_realloc()
|
|
||||||
** is a NULL pointer then its behavior is identical to calling
|
** is a NULL pointer then its behavior is identical to calling
|
||||||
** sqlite3_malloc(N) where N is the second parameter to sqlite3_realloc().
|
** sqlite3_malloc(N).
|
||||||
** ^If the second parameter to sqlite3_realloc() is zero or
|
** ^If the N parameter to sqlite3_realloc(X,N) is zero or
|
||||||
** negative then the behavior is exactly the same as calling
|
** negative then the behavior is exactly the same as calling
|
||||||
** sqlite3_free(P) where P is the first parameter to sqlite3_realloc().
|
** sqlite3_free(X).
|
||||||
** ^sqlite3_realloc() returns a pointer to a memory allocation
|
** ^sqlite3_realloc(X,N) returns a pointer to a memory allocation
|
||||||
** of at least N bytes in size or NULL if sufficient memory is unavailable.
|
** of at least N bytes in size or NULL if insufficient memory is available.
|
||||||
** ^If M is the size of the prior allocation, then min(N,M) bytes
|
** ^If M is the size of the prior allocation, then min(N,M) bytes
|
||||||
** of the prior allocation are copied into the beginning of buffer returned
|
** of the prior allocation are copied into the beginning of buffer returned
|
||||||
** by sqlite3_realloc() and the prior allocation is freed.
|
** by sqlite3_realloc(X,N) and the prior allocation is freed.
|
||||||
** ^If sqlite3_realloc() returns NULL, then the prior allocation
|
** ^If sqlite3_realloc(X,N) returns NULL and N is positive, then the
|
||||||
** is not freed.
|
** prior allocation is not freed.
|
||||||
**
|
**
|
||||||
** ^The memory returned by sqlite3_malloc() and sqlite3_realloc()
|
** ^The sqlite3_realloc64(X,N) interfaces works the same as
|
||||||
|
** sqlite3_realloc(X,N) except that N is a 64-bit unsigned integer instead
|
||||||
|
** of a 32-bit signed integer.
|
||||||
|
**
|
||||||
|
** ^If X is a memory allocation previously obtained from sqlite3_malloc(),
|
||||||
|
** sqlite3_malloc64(), sqlite3_realloc(), or sqlite3_realloc64(), then
|
||||||
|
** sqlite3_msize(X) returns the size of that memory allocation in bytes.
|
||||||
|
** ^The value returned by sqlite3_msize(X) might be larger than the number
|
||||||
|
** of bytes requested when X was allocated. ^If X is a NULL pointer then
|
||||||
|
** sqlite3_msize(X) returns zero. If X points to something that is not
|
||||||
|
** the beginning of memory allocation, or if it points to a formerly
|
||||||
|
** valid memory allocation that has now been freed, then the behavior
|
||||||
|
** of sqlite3_msize(X) is undefined and possibly harmful.
|
||||||
|
**
|
||||||
|
** ^The memory returned by sqlite3_malloc(), sqlite3_realloc(),
|
||||||
|
** sqlite3_malloc64(), and sqlite3_realloc64()
|
||||||
** is always aligned to at least an 8 byte boundary, or to a
|
** is always aligned to at least an 8 byte boundary, or to a
|
||||||
** 4 byte boundary if the [SQLITE_4_BYTE_ALIGNED_MALLOC] compile-time
|
** 4 byte boundary if the [SQLITE_4_BYTE_ALIGNED_MALLOC] compile-time
|
||||||
** option is used.
|
** option is used.
|
||||||
@ -2359,8 +2378,11 @@ SQLITE_API char *sqlite3_vsnprintf(int,char*,const char*, va_list);
|
|||||||
** [sqlite3_free()] or [sqlite3_realloc()].
|
** [sqlite3_free()] or [sqlite3_realloc()].
|
||||||
*/
|
*/
|
||||||
SQLITE_API void *sqlite3_malloc(int);
|
SQLITE_API void *sqlite3_malloc(int);
|
||||||
|
SQLITE_API void *sqlite3_malloc64(sqlite3_uint64);
|
||||||
SQLITE_API void *sqlite3_realloc(void*, int);
|
SQLITE_API void *sqlite3_realloc(void*, int);
|
||||||
|
SQLITE_API void *sqlite3_realloc64(void*, sqlite3_uint64);
|
||||||
SQLITE_API void sqlite3_free(void*);
|
SQLITE_API void sqlite3_free(void*);
|
||||||
|
SQLITE_API sqlite3_uint64 sqlite3_msize(void*);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** CAPI3REF: Memory Allocator Statistics
|
** CAPI3REF: Memory Allocator Statistics
|
||||||
@ -2647,9 +2669,9 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
|
|||||||
** an English language description of the error following a failure of any
|
** an English language description of the error following a failure of any
|
||||||
** of the sqlite3_open() routines.
|
** of the sqlite3_open() routines.
|
||||||
**
|
**
|
||||||
** ^The default encoding for the database will be UTF-8 if
|
** ^The default encoding will be UTF-8 for databases created using
|
||||||
** sqlite3_open() or sqlite3_open_v2() is called and
|
** sqlite3_open() or sqlite3_open_v2(). ^The default encoding for databases
|
||||||
** UTF-16 in the native byte order if sqlite3_open16() is used.
|
** created using sqlite3_open16() will be UTF-16 in the native byte order.
|
||||||
**
|
**
|
||||||
** Whether or not an error occurs when it is opened, resources
|
** Whether or not an error occurs when it is opened, resources
|
||||||
** associated with the [database connection] handle should be released by
|
** associated with the [database connection] handle should be released by
|
||||||
@ -2737,13 +2759,14 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
|
|||||||
** then it is interpreted as an absolute path. ^If the path does not begin
|
** then it is interpreted as an absolute path. ^If the path does not begin
|
||||||
** with a '/' (meaning that the authority section is omitted from the URI)
|
** with a '/' (meaning that the authority section is omitted from the URI)
|
||||||
** then the path is interpreted as a relative path.
|
** then the path is interpreted as a relative path.
|
||||||
** ^On windows, the first component of an absolute path
|
** ^(On windows, the first component of an absolute path
|
||||||
** is a drive specification (e.g. "C:").
|
** is a drive specification (e.g. "C:").)^
|
||||||
**
|
**
|
||||||
** [[core URI query parameters]]
|
** [[core URI query parameters]]
|
||||||
** The query component of a URI may contain parameters that are interpreted
|
** The query component of a URI may contain parameters that are interpreted
|
||||||
** either by SQLite itself, or by a [VFS | custom VFS implementation].
|
** either by SQLite itself, or by a [VFS | custom VFS implementation].
|
||||||
** SQLite interprets the following three query parameters:
|
** SQLite and its built-in [VFSes] interpret the
|
||||||
|
** following query parameters:
|
||||||
**
|
**
|
||||||
** <ul>
|
** <ul>
|
||||||
** <li> <b>vfs</b>: ^The "vfs" parameter may be used to specify the name of
|
** <li> <b>vfs</b>: ^The "vfs" parameter may be used to specify the name of
|
||||||
@ -2778,11 +2801,9 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
|
|||||||
** a URI filename, its value overrides any behavior requested by setting
|
** a URI filename, its value overrides any behavior requested by setting
|
||||||
** SQLITE_OPEN_PRIVATECACHE or SQLITE_OPEN_SHAREDCACHE flag.
|
** SQLITE_OPEN_PRIVATECACHE or SQLITE_OPEN_SHAREDCACHE flag.
|
||||||
**
|
**
|
||||||
** <li> <b>psow</b>: ^The psow parameter may be "true" (or "on" or "yes" or
|
** <li> <b>psow</b>: ^The psow parameter indicates whether or not the
|
||||||
** "1") or "false" (or "off" or "no" or "0") to indicate that the
|
|
||||||
** [powersafe overwrite] property does or does not apply to the
|
** [powersafe overwrite] property does or does not apply to the
|
||||||
** storage media on which the database file resides. ^The psow query
|
** storage media on which the database file resides.
|
||||||
** parameter only works for the built-in unix and Windows VFSes.
|
|
||||||
**
|
**
|
||||||
** <li> <b>nolock</b>: ^The nolock parameter is a boolean query parameter
|
** <li> <b>nolock</b>: ^The nolock parameter is a boolean query parameter
|
||||||
** which if set disables file locking in rollback journal modes. This
|
** which if set disables file locking in rollback journal modes. This
|
||||||
@ -3078,6 +3099,10 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
|
|||||||
**
|
**
|
||||||
** [[SQLITE_LIMIT_TRIGGER_DEPTH]] ^(<dt>SQLITE_LIMIT_TRIGGER_DEPTH</dt>
|
** [[SQLITE_LIMIT_TRIGGER_DEPTH]] ^(<dt>SQLITE_LIMIT_TRIGGER_DEPTH</dt>
|
||||||
** <dd>The maximum depth of recursion for triggers.</dd>)^
|
** <dd>The maximum depth of recursion for triggers.</dd>)^
|
||||||
|
**
|
||||||
|
** [[SQLITE_LIMIT_WORKER_THREADS]] ^(<dt>SQLITE_LIMIT_WORKER_THREADS</dt>
|
||||||
|
** <dd>The maximum number of auxiliary worker threads that a single
|
||||||
|
** [prepared statement] may start.</dd>)^
|
||||||
** </dl>
|
** </dl>
|
||||||
*/
|
*/
|
||||||
#define SQLITE_LIMIT_LENGTH 0
|
#define SQLITE_LIMIT_LENGTH 0
|
||||||
@ -3091,6 +3116,7 @@ SQLITE_API int sqlite3_limit(sqlite3*, int id, int newVal);
|
|||||||
#define SQLITE_LIMIT_LIKE_PATTERN_LENGTH 8
|
#define SQLITE_LIMIT_LIKE_PATTERN_LENGTH 8
|
||||||
#define SQLITE_LIMIT_VARIABLE_NUMBER 9
|
#define SQLITE_LIMIT_VARIABLE_NUMBER 9
|
||||||
#define SQLITE_LIMIT_TRIGGER_DEPTH 10
|
#define SQLITE_LIMIT_TRIGGER_DEPTH 10
|
||||||
|
#define SQLITE_LIMIT_WORKER_THREADS 11
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** CAPI3REF: Compiling An SQL Statement
|
** CAPI3REF: Compiling An SQL Statement
|
||||||
@ -3364,18 +3390,18 @@ typedef struct sqlite3_context sqlite3_context;
|
|||||||
** If the fourth parameter to sqlite3_bind_blob() is negative, then
|
** If the fourth parameter to sqlite3_bind_blob() is negative, then
|
||||||
** the behavior is undefined.
|
** the behavior is undefined.
|
||||||
** If a non-negative fourth parameter is provided to sqlite3_bind_text()
|
** If a non-negative fourth parameter is provided to sqlite3_bind_text()
|
||||||
** or sqlite3_bind_text16() then that parameter must be the byte offset
|
** or sqlite3_bind_text16() or sqlite3_bind_text64() then
|
||||||
|
** that parameter must be the byte offset
|
||||||
** where the NUL terminator would occur assuming the string were NUL
|
** where the NUL terminator would occur assuming the string were NUL
|
||||||
** terminated. If any NUL characters occur at byte offsets less than
|
** terminated. If any NUL characters occur at byte offsets less than
|
||||||
** the value of the fourth parameter then the resulting string value will
|
** the value of the fourth parameter then the resulting string value will
|
||||||
** contain embedded NULs. The result of expressions involving strings
|
** contain embedded NULs. The result of expressions involving strings
|
||||||
** with embedded NULs is undefined.
|
** with embedded NULs is undefined.
|
||||||
**
|
**
|
||||||
** ^The fifth argument to sqlite3_bind_blob(), sqlite3_bind_text(), and
|
** ^The fifth argument to the BLOB and string binding interfaces
|
||||||
** sqlite3_bind_text16() is a destructor used to dispose of the BLOB or
|
** is a destructor used to dispose of the BLOB or
|
||||||
** string after SQLite has finished with it. ^The destructor is called
|
** string after SQLite has finished with it. ^The destructor is called
|
||||||
** to dispose of the BLOB or string even if the call to sqlite3_bind_blob(),
|
** to dispose of the BLOB or string even if the call to bind API fails.
|
||||||
** sqlite3_bind_text(), or sqlite3_bind_text16() fails.
|
|
||||||
** ^If the fifth argument is
|
** ^If the fifth argument is
|
||||||
** the special value [SQLITE_STATIC], then SQLite assumes that the
|
** the special value [SQLITE_STATIC], then SQLite assumes that the
|
||||||
** information is in static, unmanaged space and does not need to be freed.
|
** information is in static, unmanaged space and does not need to be freed.
|
||||||
@ -3383,6 +3409,14 @@ typedef struct sqlite3_context sqlite3_context;
|
|||||||
** SQLite makes its own private copy of the data immediately, before
|
** SQLite makes its own private copy of the data immediately, before
|
||||||
** the sqlite3_bind_*() routine returns.
|
** the sqlite3_bind_*() routine returns.
|
||||||
**
|
**
|
||||||
|
** ^The sixth argument to sqlite3_bind_text64() must be one of
|
||||||
|
** [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE]
|
||||||
|
** to specify the encoding of the text in the third parameter. If
|
||||||
|
** the sixth argument to sqlite3_bind_text64() is not one of the
|
||||||
|
** allowed values shown above, or if the text encoding is different
|
||||||
|
** from the encoding specified by the sixth parameter, then the behavior
|
||||||
|
** is undefined.
|
||||||
|
**
|
||||||
** ^The sqlite3_bind_zeroblob() routine binds a BLOB of length N that
|
** ^The sqlite3_bind_zeroblob() routine binds a BLOB of length N that
|
||||||
** is filled with zeroes. ^A zeroblob uses a fixed amount of memory
|
** is filled with zeroes. ^A zeroblob uses a fixed amount of memory
|
||||||
** (just an integer to hold its size) while it is being processed.
|
** (just an integer to hold its size) while it is being processed.
|
||||||
@ -3403,6 +3437,9 @@ typedef struct sqlite3_context sqlite3_context;
|
|||||||
**
|
**
|
||||||
** ^The sqlite3_bind_* routines return [SQLITE_OK] on success or an
|
** ^The sqlite3_bind_* routines return [SQLITE_OK] on success or an
|
||||||
** [error code] if anything goes wrong.
|
** [error code] if anything goes wrong.
|
||||||
|
** ^[SQLITE_TOOBIG] might be returned if the size of a string or BLOB
|
||||||
|
** exceeds limits imposed by [sqlite3_limit]([SQLITE_LIMIT_LENGTH]) or
|
||||||
|
** [SQLITE_MAX_LENGTH].
|
||||||
** ^[SQLITE_RANGE] is returned if the parameter
|
** ^[SQLITE_RANGE] is returned if the parameter
|
||||||
** index is out of range. ^[SQLITE_NOMEM] is returned if malloc() fails.
|
** index is out of range. ^[SQLITE_NOMEM] is returned if malloc() fails.
|
||||||
**
|
**
|
||||||
@ -3410,12 +3447,16 @@ typedef struct sqlite3_context sqlite3_context;
|
|||||||
** [sqlite3_bind_parameter_name()], and [sqlite3_bind_parameter_index()].
|
** [sqlite3_bind_parameter_name()], and [sqlite3_bind_parameter_index()].
|
||||||
*/
|
*/
|
||||||
SQLITE_API int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*));
|
SQLITE_API int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*));
|
||||||
|
SQLITE_API int sqlite3_bind_blob64(sqlite3_stmt*, int, const void*, sqlite3_uint64,
|
||||||
|
void(*)(void*));
|
||||||
SQLITE_API int sqlite3_bind_double(sqlite3_stmt*, int, double);
|
SQLITE_API int sqlite3_bind_double(sqlite3_stmt*, int, double);
|
||||||
SQLITE_API int sqlite3_bind_int(sqlite3_stmt*, int, int);
|
SQLITE_API int sqlite3_bind_int(sqlite3_stmt*, int, int);
|
||||||
SQLITE_API int sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64);
|
SQLITE_API int sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64);
|
||||||
SQLITE_API int sqlite3_bind_null(sqlite3_stmt*, int);
|
SQLITE_API int sqlite3_bind_null(sqlite3_stmt*, int);
|
||||||
SQLITE_API int sqlite3_bind_text(sqlite3_stmt*, int, const char*, int n, void(*)(void*));
|
SQLITE_API int sqlite3_bind_text(sqlite3_stmt*,int,const char*,int,void(*)(void*));
|
||||||
SQLITE_API int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*));
|
SQLITE_API int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*));
|
||||||
|
SQLITE_API int sqlite3_bind_text64(sqlite3_stmt*, int, const char*, sqlite3_uint64,
|
||||||
|
void(*)(void*), unsigned char encoding);
|
||||||
SQLITE_API int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*);
|
SQLITE_API int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*);
|
||||||
SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n);
|
SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n);
|
||||||
|
|
||||||
@ -4164,7 +4205,7 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int6
|
|||||||
** object results in undefined behavior.
|
** object results in undefined behavior.
|
||||||
**
|
**
|
||||||
** ^These routines work just like the corresponding [column access functions]
|
** ^These routines work just like the corresponding [column access functions]
|
||||||
** except that these routines take a single [protected sqlite3_value] object
|
** except that these routines take a single [protected sqlite3_value] object
|
||||||
** pointer instead of a [sqlite3_stmt*] pointer and an integer column number.
|
** pointer instead of a [sqlite3_stmt*] pointer and an integer column number.
|
||||||
**
|
**
|
||||||
** ^The sqlite3_value_text16() interface extracts a UTF-16 string
|
** ^The sqlite3_value_text16() interface extracts a UTF-16 string
|
||||||
@ -4411,6 +4452,10 @@ typedef void (*sqlite3_destructor_type)(void*);
|
|||||||
** set the return value of the application-defined function to be
|
** set the return value of the application-defined function to be
|
||||||
** a text string which is represented as UTF-8, UTF-16 native byte order,
|
** a text string which is represented as UTF-8, UTF-16 native byte order,
|
||||||
** UTF-16 little endian, or UTF-16 big endian, respectively.
|
** UTF-16 little endian, or UTF-16 big endian, respectively.
|
||||||
|
** ^The sqlite3_result_text64() interface sets the return value of an
|
||||||
|
** application-defined function to be a text string in an encoding
|
||||||
|
** specified by the fifth (and last) parameter, which must be one
|
||||||
|
** of [SQLITE_UTF8], [SQLITE_UTF16], [SQLITE_UTF16BE], or [SQLITE_UTF16LE].
|
||||||
** ^SQLite takes the text result from the application from
|
** ^SQLite takes the text result from the application from
|
||||||
** the 2nd parameter of the sqlite3_result_text* interfaces.
|
** the 2nd parameter of the sqlite3_result_text* interfaces.
|
||||||
** ^If the 3rd parameter to the sqlite3_result_text* interfaces
|
** ^If the 3rd parameter to the sqlite3_result_text* interfaces
|
||||||
@ -4454,6 +4499,7 @@ typedef void (*sqlite3_destructor_type)(void*);
|
|||||||
** the [sqlite3_context] pointer, the results are undefined.
|
** the [sqlite3_context] pointer, the results are undefined.
|
||||||
*/
|
*/
|
||||||
SQLITE_API void sqlite3_result_blob(sqlite3_context*, const void*, int, void(*)(void*));
|
SQLITE_API void sqlite3_result_blob(sqlite3_context*, const void*, int, void(*)(void*));
|
||||||
|
SQLITE_API void sqlite3_result_blob64(sqlite3_context*,const void*,sqlite3_uint64,void(*)(void*));
|
||||||
SQLITE_API void sqlite3_result_double(sqlite3_context*, double);
|
SQLITE_API void sqlite3_result_double(sqlite3_context*, double);
|
||||||
SQLITE_API void sqlite3_result_error(sqlite3_context*, const char*, int);
|
SQLITE_API void sqlite3_result_error(sqlite3_context*, const char*, int);
|
||||||
SQLITE_API void sqlite3_result_error16(sqlite3_context*, const void*, int);
|
SQLITE_API void sqlite3_result_error16(sqlite3_context*, const void*, int);
|
||||||
@ -4464,6 +4510,8 @@ SQLITE_API void sqlite3_result_int(sqlite3_context*, int);
|
|||||||
SQLITE_API void sqlite3_result_int64(sqlite3_context*, sqlite3_int64);
|
SQLITE_API void sqlite3_result_int64(sqlite3_context*, sqlite3_int64);
|
||||||
SQLITE_API void sqlite3_result_null(sqlite3_context*);
|
SQLITE_API void sqlite3_result_null(sqlite3_context*);
|
||||||
SQLITE_API void sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*));
|
SQLITE_API void sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*));
|
||||||
|
SQLITE_API void sqlite3_result_text64(sqlite3_context*, const char*,sqlite3_uint64,
|
||||||
|
void(*)(void*), unsigned char encoding);
|
||||||
SQLITE_API void sqlite3_result_text16(sqlite3_context*, const void*, int, void(*)(void*));
|
SQLITE_API void sqlite3_result_text16(sqlite3_context*, const void*, int, void(*)(void*));
|
||||||
SQLITE_API void sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*));
|
SQLITE_API void sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*));
|
||||||
SQLITE_API void sqlite3_result_text16be(sqlite3_context*, const void*, int,void(*)(void*));
|
SQLITE_API void sqlite3_result_text16be(sqlite3_context*, const void*, int,void(*)(void*));
|
||||||
@ -6160,12 +6208,13 @@ SQLITE_API int sqlite3_test_control(int op, ...);
|
|||||||
#define SQLITE_TESTCTRL_ISKEYWORD 16
|
#define SQLITE_TESTCTRL_ISKEYWORD 16
|
||||||
#define SQLITE_TESTCTRL_SCRATCHMALLOC 17
|
#define SQLITE_TESTCTRL_SCRATCHMALLOC 17
|
||||||
#define SQLITE_TESTCTRL_LOCALTIME_FAULT 18
|
#define SQLITE_TESTCTRL_LOCALTIME_FAULT 18
|
||||||
#define SQLITE_TESTCTRL_EXPLAIN_STMT 19
|
#define SQLITE_TESTCTRL_EXPLAIN_STMT 19 /* NOT USED */
|
||||||
#define SQLITE_TESTCTRL_NEVER_CORRUPT 20
|
#define SQLITE_TESTCTRL_NEVER_CORRUPT 20
|
||||||
#define SQLITE_TESTCTRL_VDBE_COVERAGE 21
|
#define SQLITE_TESTCTRL_VDBE_COVERAGE 21
|
||||||
#define SQLITE_TESTCTRL_BYTEORDER 22
|
#define SQLITE_TESTCTRL_BYTEORDER 22
|
||||||
#define SQLITE_TESTCTRL_ISINIT 23
|
#define SQLITE_TESTCTRL_ISINIT 23
|
||||||
#define SQLITE_TESTCTRL_LAST 23
|
#define SQLITE_TESTCTRL_SORTER_MMAP 24
|
||||||
|
#define SQLITE_TESTCTRL_LAST 24
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** CAPI3REF: SQLite Runtime Status
|
** CAPI3REF: SQLite Runtime Status
|
||||||
@ -6356,12 +6405,12 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
|
|||||||
** the current value is always zero.)^
|
** the current value is always zero.)^
|
||||||
**
|
**
|
||||||
** [[SQLITE_DBSTATUS_CACHE_USED]] ^(<dt>SQLITE_DBSTATUS_CACHE_USED</dt>
|
** [[SQLITE_DBSTATUS_CACHE_USED]] ^(<dt>SQLITE_DBSTATUS_CACHE_USED</dt>
|
||||||
** <dd>This parameter returns the approximate number of of bytes of heap
|
** <dd>This parameter returns the approximate number of bytes of heap
|
||||||
** memory used by all pager caches associated with the database connection.)^
|
** memory used by all pager caches associated with the database connection.)^
|
||||||
** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0.
|
** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0.
|
||||||
**
|
**
|
||||||
** [[SQLITE_DBSTATUS_SCHEMA_USED]] ^(<dt>SQLITE_DBSTATUS_SCHEMA_USED</dt>
|
** [[SQLITE_DBSTATUS_SCHEMA_USED]] ^(<dt>SQLITE_DBSTATUS_SCHEMA_USED</dt>
|
||||||
** <dd>This parameter returns the approximate number of of bytes of heap
|
** <dd>This parameter returns the approximate number of bytes of heap
|
||||||
** memory used to store the schema for all databases associated
|
** memory used to store the schema for all databases associated
|
||||||
** with the connection - main, temp, and any [ATTACH]-ed databases.)^
|
** with the connection - main, temp, and any [ATTACH]-ed databases.)^
|
||||||
** ^The full amount of memory used by the schemas is reported, even if the
|
** ^The full amount of memory used by the schemas is reported, even if the
|
||||||
@ -6370,7 +6419,7 @@ SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int r
|
|||||||
** ^The highwater mark associated with SQLITE_DBSTATUS_SCHEMA_USED is always 0.
|
** ^The highwater mark associated with SQLITE_DBSTATUS_SCHEMA_USED is always 0.
|
||||||
**
|
**
|
||||||
** [[SQLITE_DBSTATUS_STMT_USED]] ^(<dt>SQLITE_DBSTATUS_STMT_USED</dt>
|
** [[SQLITE_DBSTATUS_STMT_USED]] ^(<dt>SQLITE_DBSTATUS_STMT_USED</dt>
|
||||||
** <dd>This parameter returns the approximate number of of bytes of heap
|
** <dd>This parameter returns the approximate number of bytes of heap
|
||||||
** and lookaside memory used by all prepared statements associated with
|
** and lookaside memory used by all prepared statements associated with
|
||||||
** the database connection.)^
|
** the database connection.)^
|
||||||
** ^The highwater mark associated with SQLITE_DBSTATUS_STMT_USED is always 0.
|
** ^The highwater mark associated with SQLITE_DBSTATUS_STMT_USED is always 0.
|
||||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -4,10 +4,10 @@
|
|||||||
android:installLocation="auto">
|
android:installLocation="auto">
|
||||||
|
|
||||||
<supports-screens android:anyDensity="true"
|
<supports-screens android:anyDensity="true"
|
||||||
android:smallScreens="true"
|
|
||||||
android:normalScreens="true"
|
|
||||||
android:largeScreens="true"
|
android:largeScreens="true"
|
||||||
|
android:normalScreens="true"
|
||||||
android:resizeable="true"
|
android:resizeable="true"
|
||||||
|
android:smallScreens="true"
|
||||||
android:xlargeScreens="true"/>
|
android:xlargeScreens="true"/>
|
||||||
|
|
||||||
<uses-feature android:glEsVersion="0x00020000" android:required="false"/>
|
<uses-feature android:glEsVersion="0x00020000" android:required="false"/>
|
||||||
@ -41,20 +41,20 @@
|
|||||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
|
android:name=".ApplicationLoader"
|
||||||
android:allowBackup="false"
|
android:allowBackup="false"
|
||||||
|
android:hardwareAccelerated="true"
|
||||||
android:icon="@drawable/ic_launcher"
|
android:icon="@drawable/ic_launcher"
|
||||||
android:label="@string/AppName"
|
android:label="@string/AppName"
|
||||||
android:theme="@style/Theme.TMessages.Start"
|
android:largeHeap="true"
|
||||||
android:name="org.telegram.ui.ApplicationLoader"
|
android:theme="@style/Theme.TMessages.Start">
|
||||||
android:hardwareAccelerated="true"
|
|
||||||
android:largeHeap="true">
|
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name="org.telegram.ui.LaunchActivity"
|
android:name="org.telegram.ui.LaunchActivity"
|
||||||
android:windowSoftInputMode="adjustResize"
|
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
|
||||||
android:hardwareAccelerated="true"
|
android:hardwareAccelerated="true"
|
||||||
android:launchMode="singleTask"
|
android:launchMode="singleTask"
|
||||||
android:configChanges="keyboard|keyboardHidden|orientation|screenSize">
|
android:windowSoftInputMode="adjustPan">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
@ -95,6 +95,19 @@
|
|||||||
<category android:name="android.intent.category.DEFAULT"/>
|
<category android:name="android.intent.category.DEFAULT"/>
|
||||||
<data android:mimeType="vnd.android.cursor.item/vnd.org.telegram.messenger.android.profile"/>
|
<data android:mimeType="vnd.android.cursor.item/vnd.org.telegram.messenger.android.profile"/>
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.VIEW"/>
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
<data android:host="telegram.me" android:scheme="http" />
|
||||||
|
<data android:host="telegram.me" android:scheme="https" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter android:icon="@drawable/ic_launcher" android:priority="1">
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<data android:scheme="tg" />
|
||||||
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
android:name="org.telegram.ui.IntroActivity"
|
android:name="org.telegram.ui.IntroActivity"
|
||||||
@ -105,9 +118,9 @@
|
|||||||
android:configChanges="keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize"
|
android:configChanges="keyboard|keyboardHidden|navigation|orientation|screenLayout|uiMode|screenSize|smallestScreenSize"
|
||||||
android:excludeFromRecents="true"
|
android:excludeFromRecents="true"
|
||||||
android:launchMode="singleTask"
|
android:launchMode="singleTask"
|
||||||
android:windowSoftInputMode="adjustResize|stateHidden"
|
|
||||||
android:taskAffinity=""
|
android:taskAffinity=""
|
||||||
android:theme="@style/Theme.TMessages.PopupNotification">
|
android:theme="@style/Theme.TMessages.PopupNotification"
|
||||||
|
android:windowSoftInputMode="adjustResize|stateHidden">
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<receiver android:name="org.telegram.android.SmsListener">
|
<receiver android:name="org.telegram.android.SmsListener">
|
||||||
@ -116,8 +129,7 @@
|
|||||||
</intent-filter>
|
</intent-filter>
|
||||||
</receiver>
|
</receiver>
|
||||||
|
|
||||||
<service android:name="org.telegram.android.AuthenticatorService"
|
<service android:name="org.telegram.android.AuthenticatorService" android:exported="true">
|
||||||
android:exported="true">
|
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.accounts.AccountAuthenticator"/>
|
<action android:name="android.accounts.AccountAuthenticator"/>
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
@ -125,8 +137,7 @@
|
|||||||
android:resource="@xml/auth"/>
|
android:resource="@xml/auth"/>
|
||||||
</service>
|
</service>
|
||||||
|
|
||||||
<service android:name="org.telegram.android.ContactsSyncAdapterService"
|
<service android:name="org.telegram.android.ContactsSyncAdapterService" android:exported="true">
|
||||||
android:exported="true">
|
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.content.SyncAdapter" />
|
<action android:name="android.content.SyncAdapter" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
Binary file not shown.
@ -24,7 +24,7 @@
|
|||||||
|
|
||||||
package org.telegram.PhoneFormat;
|
package org.telegram.PhoneFormat;
|
||||||
|
|
||||||
import org.telegram.ui.ApplicationLoader;
|
import org.telegram.messenger.ApplicationLoader;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
package org.telegram.SQLite;
|
package org.telegram.SQLite;
|
||||||
|
|
||||||
import org.telegram.messenger.FileLog;
|
import org.telegram.messenger.FileLog;
|
||||||
import org.telegram.ui.ApplicationLoader;
|
import org.telegram.messenger.ApplicationLoader;
|
||||||
|
|
||||||
public class SQLiteDatabase {
|
public class SQLiteDatabase {
|
||||||
private final int sqliteHandle;
|
private final int sqliteHandle;
|
||||||
|
@ -15,28 +15,38 @@ import android.content.DialogInterface;
|
|||||||
import android.content.pm.ActivityInfo;
|
import android.content.pm.ActivityInfo;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
import android.graphics.Point;
|
import android.graphics.Point;
|
||||||
|
import android.graphics.Rect;
|
||||||
import android.graphics.Typeface;
|
import android.graphics.Typeface;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Environment;
|
import android.os.Environment;
|
||||||
|
import android.text.Spannable;
|
||||||
|
import android.text.SpannableStringBuilder;
|
||||||
|
import android.text.Spanned;
|
||||||
|
import android.util.StateSet;
|
||||||
import android.view.Display;
|
import android.view.Display;
|
||||||
import android.view.Surface;
|
import android.view.Surface;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
import android.view.inputmethod.InputMethodManager;
|
import android.view.inputmethod.InputMethodManager;
|
||||||
|
import android.widget.AbsListView;
|
||||||
|
import android.widget.EdgeEffect;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
|
import android.widget.ListView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import org.telegram.messenger.FileLog;
|
import org.telegram.messenger.FileLog;
|
||||||
import org.telegram.messenger.R;
|
import org.telegram.messenger.R;
|
||||||
import org.telegram.messenger.TLRPC;
|
import org.telegram.messenger.TLRPC;
|
||||||
import org.telegram.messenger.UserConfig;
|
import org.telegram.messenger.ApplicationLoader;
|
||||||
import org.telegram.ui.ApplicationLoader;
|
import org.telegram.ui.Components.NumberPicker;
|
||||||
import org.telegram.ui.Views.NumberPicker;
|
import org.telegram.ui.Components.TypefaceSpan;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Hashtable;
|
import java.util.Hashtable;
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
public class AndroidUtilities {
|
public class AndroidUtilities {
|
||||||
|
|
||||||
@ -51,37 +61,6 @@ public class AndroidUtilities {
|
|||||||
public static Integer photoSize = null;
|
public static Integer photoSize = null;
|
||||||
private static Boolean isTablet = null;
|
private static Boolean isTablet = null;
|
||||||
|
|
||||||
public static int[] arrColors = {0xffee4928, 0xff41a903, 0xffe09602, 0xff0f94ed, 0xff8f3bf7, 0xfffc4380, 0xff00a1c4, 0xffeb7002};
|
|
||||||
public static int[] arrUsersAvatars = {
|
|
||||||
R.drawable.user_red,
|
|
||||||
R.drawable.user_green,
|
|
||||||
R.drawable.user_yellow,
|
|
||||||
R.drawable.user_blue,
|
|
||||||
R.drawable.user_violet,
|
|
||||||
R.drawable.user_pink,
|
|
||||||
R.drawable.user_aqua,
|
|
||||||
R.drawable.user_orange};
|
|
||||||
|
|
||||||
public static int[] arrGroupsAvatars = {
|
|
||||||
R.drawable.group_red,
|
|
||||||
R.drawable.group_green,
|
|
||||||
R.drawable.group_yellow,
|
|
||||||
R.drawable.group_blue,
|
|
||||||
R.drawable.group_violet,
|
|
||||||
R.drawable.group_pink,
|
|
||||||
R.drawable.group_aqua,
|
|
||||||
R.drawable.group_orange};
|
|
||||||
|
|
||||||
public static int[] arrBroadcastAvatars = {
|
|
||||||
R.drawable.broadcast_red,
|
|
||||||
R.drawable.broadcast_green,
|
|
||||||
R.drawable.broadcast_yellow,
|
|
||||||
R.drawable.broadcast_blue,
|
|
||||||
R.drawable.broadcast_violet,
|
|
||||||
R.drawable.broadcast_pink,
|
|
||||||
R.drawable.broadcast_aqua,
|
|
||||||
R.drawable.broadcast_orange};
|
|
||||||
|
|
||||||
static {
|
static {
|
||||||
density = ApplicationLoader.applicationContext.getResources().getDisplayMetrics().density;
|
density = ApplicationLoader.applicationContext.getResources().getDisplayMetrics().density;
|
||||||
checkDisplaySize();
|
checkDisplaySize();
|
||||||
@ -97,24 +76,22 @@ public class AndroidUtilities {
|
|||||||
if (manager != null && manager.getDefaultDisplay() != null) {
|
if (manager != null && manager.getDefaultDisplay() != null) {
|
||||||
int rotation = manager.getDefaultDisplay().getRotation();
|
int rotation = manager.getDefaultDisplay().getRotation();
|
||||||
int orientation = activity.getResources().getConfiguration().orientation;
|
int orientation = activity.getResources().getConfiguration().orientation;
|
||||||
|
int SCREEN_ORIENTATION_REVERSE_LANDSCAPE = 8;
|
||||||
|
int SCREEN_ORIENTATION_REVERSE_PORTRAIT = 9;
|
||||||
|
if (Build.VERSION.SDK_INT < 9) {
|
||||||
|
SCREEN_ORIENTATION_REVERSE_LANDSCAPE = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
|
||||||
|
SCREEN_ORIENTATION_REVERSE_PORTRAIT = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
|
||||||
|
}
|
||||||
|
|
||||||
if (rotation == Surface.ROTATION_270) {
|
if (rotation == Surface.ROTATION_270) {
|
||||||
if (orientation == Configuration.ORIENTATION_PORTRAIT) {
|
if (orientation == Configuration.ORIENTATION_PORTRAIT) {
|
||||||
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
|
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
|
||||||
} else {
|
} else {
|
||||||
if (Build.VERSION.SDK_INT >= 9) {
|
activity.setRequestedOrientation(SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
|
||||||
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
|
|
||||||
} else {
|
|
||||||
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if (rotation == Surface.ROTATION_90) {
|
} else if (rotation == Surface.ROTATION_90) {
|
||||||
if (orientation == Configuration.ORIENTATION_PORTRAIT) {
|
if (orientation == Configuration.ORIENTATION_PORTRAIT) {
|
||||||
if (Build.VERSION.SDK_INT >= 9) {
|
activity.setRequestedOrientation(SCREEN_ORIENTATION_REVERSE_PORTRAIT);
|
||||||
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT);
|
|
||||||
} else {
|
|
||||||
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
|
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
|
||||||
}
|
}
|
||||||
@ -126,17 +103,9 @@ public class AndroidUtilities {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
||||||
if (Build.VERSION.SDK_INT >= 9) {
|
activity.setRequestedOrientation(SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
|
||||||
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
|
|
||||||
} else {
|
|
||||||
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (Build.VERSION.SDK_INT >= 9) {
|
activity.setRequestedOrientation(SCREEN_ORIENTATION_REVERSE_PORTRAIT);
|
||||||
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT);
|
|
||||||
} else {
|
|
||||||
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -239,11 +208,7 @@ public class AndroidUtilities {
|
|||||||
return new File("");
|
return new File("");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int dp(int value) {
|
public static int dp(float value) {
|
||||||
return (int)(Math.max(1, density * value));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int dpf(float value) {
|
|
||||||
return (int)Math.ceil(density * value);
|
return (int)Math.ceil(density * value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -290,11 +255,11 @@ public class AndroidUtilities {
|
|||||||
return layer & 0x0000ffff | (version << 16);
|
return layer & 0x0000ffff | (version << 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void RunOnUIThread(Runnable runnable) {
|
public static void runOnUIThread(Runnable runnable) {
|
||||||
RunOnUIThread(runnable, 0);
|
runOnUIThread(runnable, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void RunOnUIThread(Runnable runnable, long delay) {
|
public static void runOnUIThread(Runnable runnable, long delay) {
|
||||||
if (delay == 0) {
|
if (delay == 0) {
|
||||||
ApplicationLoader.applicationHandler.post(runnable);
|
ApplicationLoader.applicationHandler.post(runnable);
|
||||||
} else {
|
} else {
|
||||||
@ -302,7 +267,7 @@ public class AndroidUtilities {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void CancelRunOnUIThread(Runnable runnable) {
|
public static void cancelRunOnUIThread(Runnable runnable) {
|
||||||
ApplicationLoader.applicationHandler.removeCallbacks(runnable);
|
ApplicationLoader.applicationHandler.removeCallbacks(runnable);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -337,58 +302,6 @@ public class AndroidUtilities {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int getColorIndex(int id) {
|
|
||||||
int[] arr;
|
|
||||||
if (id >= 0) {
|
|
||||||
arr = arrUsersAvatars;
|
|
||||||
} else {
|
|
||||||
arr = arrGroupsAvatars;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
String str;
|
|
||||||
if (id >= 0) {
|
|
||||||
str = String.format(Locale.US, "%d%d", id, UserConfig.getClientUserId());
|
|
||||||
} else {
|
|
||||||
str = String.format(Locale.US, "%d", id);
|
|
||||||
}
|
|
||||||
if (str.length() > 15) {
|
|
||||||
str = str.substring(0, 15);
|
|
||||||
}
|
|
||||||
java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5");
|
|
||||||
byte[] digest = md.digest(str.getBytes());
|
|
||||||
int b = digest[Math.abs(id % 16)];
|
|
||||||
if (b < 0) {
|
|
||||||
b += 256;
|
|
||||||
}
|
|
||||||
return Math.abs(b) % arr.length;
|
|
||||||
} catch (Exception e) {
|
|
||||||
FileLog.e("tmessages", e);
|
|
||||||
}
|
|
||||||
return id % arr.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int getColorForId(int id) {
|
|
||||||
if (id / 1000 == 333) {
|
|
||||||
return 0xff0f94ed;
|
|
||||||
}
|
|
||||||
return arrColors[getColorIndex(id)];
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int getUserAvatarForId(int id) {
|
|
||||||
if (id / 1000 == 333 || id / 1000 == 777) {
|
|
||||||
return R.drawable.telegram_avatar;
|
|
||||||
}
|
|
||||||
return arrUsersAvatars[getColorIndex(id)];
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int getGroupAvatarForId(int id) {
|
|
||||||
return arrGroupsAvatars[getColorIndex(-Math.abs(id))];
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int getBroadcastAvatarForId(int id) {
|
|
||||||
return arrBroadcastAvatars[getColorIndex(-Math.abs(id))];
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int getPhotoSize() {
|
public static int getPhotoSize() {
|
||||||
if (photoSize == null) {
|
if (photoSize == null) {
|
||||||
if (Build.VERSION.SDK_INT >= 16) {
|
if (Build.VERSION.SDK_INT >= 16) {
|
||||||
@ -438,7 +351,7 @@ public class AndroidUtilities {
|
|||||||
} else if (encryptedChat.ttl == 60 * 60 * 24 * 7) {
|
} else if (encryptedChat.ttl == 60 * 60 * 24 * 7) {
|
||||||
numberPicker.setValue(20);
|
numberPicker.setValue(20);
|
||||||
} else if (encryptedChat.ttl == 0) {
|
} else if (encryptedChat.ttl == 0) {
|
||||||
numberPicker.setValue(5);
|
numberPicker.setValue(0);
|
||||||
}
|
}
|
||||||
numberPicker.setFormatter(new NumberPicker.Formatter() {
|
numberPicker.setFormatter(new NumberPicker.Formatter() {
|
||||||
@Override
|
@Override
|
||||||
@ -481,7 +394,7 @@ public class AndroidUtilities {
|
|||||||
encryptedChat.ttl = 60 * 60 * 24 * 7;
|
encryptedChat.ttl = 60 * 60 * 24 * 7;
|
||||||
}
|
}
|
||||||
if (oldValue != encryptedChat.ttl) {
|
if (oldValue != encryptedChat.ttl) {
|
||||||
SendMessagesHelper.getInstance().sendTTLMessage(encryptedChat, null);
|
SecretChatHelper.getInstance().sendTTLMessage(encryptedChat, null);
|
||||||
MessagesStorage.getInstance().updateEncryptedChatTTL(encryptedChat);
|
MessagesStorage.getInstance().updateEncryptedChatTTL(encryptedChat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -501,4 +414,114 @@ public class AndroidUtilities {
|
|||||||
FileLog.e("tmessages", e);
|
FileLog.e("tmessages", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int getViewInset(View view) {
|
||||||
|
if (view == null || Build.VERSION.SDK_INT < 21) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Field mAttachInfoField = View.class.getDeclaredField("mAttachInfo");
|
||||||
|
mAttachInfoField.setAccessible(true);
|
||||||
|
Object mAttachInfo = mAttachInfoField.get(view);
|
||||||
|
if (mAttachInfo != null) {
|
||||||
|
Field mStableInsetsField = mAttachInfo.getClass().getDeclaredField("mStableInsets");
|
||||||
|
mStableInsetsField.setAccessible(true);
|
||||||
|
Rect insets = (Rect)mStableInsetsField.get(mAttachInfo);
|
||||||
|
return insets.bottom;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
FileLog.e("tmessages", e);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getCurrentActionBarHeight() {
|
||||||
|
if (isTablet()) {
|
||||||
|
return dp(64);
|
||||||
|
} else if (ApplicationLoader.applicationContext.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
||||||
|
return dp(48);
|
||||||
|
} else {
|
||||||
|
return dp(56);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Point getRealScreenSize() {
|
||||||
|
Point size = new Point();
|
||||||
|
try {
|
||||||
|
WindowManager windowManager = (WindowManager) ApplicationLoader.applicationContext.getSystemService(Context.WINDOW_SERVICE);
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||||
|
windowManager.getDefaultDisplay().getRealSize(size);
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
Method mGetRawW = Display.class.getMethod("getRawWidth");
|
||||||
|
Method mGetRawH = Display.class.getMethod("getRawHeight");
|
||||||
|
size.set((Integer) mGetRawW.invoke(windowManager.getDefaultDisplay()), (Integer) mGetRawH.invoke(windowManager.getDefaultDisplay()));
|
||||||
|
} catch (Exception e) {
|
||||||
|
size.set(windowManager.getDefaultDisplay().getWidth(), windowManager.getDefaultDisplay().getHeight());
|
||||||
|
FileLog.e("tmessages", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
FileLog.e("tmessages", e);
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setListViewEdgeEffectColor(AbsListView listView, int color) {
|
||||||
|
if (Build.VERSION.SDK_INT >= 21) {
|
||||||
|
try {
|
||||||
|
Field field = AbsListView.class.getDeclaredField("mEdgeGlowTop");
|
||||||
|
field.setAccessible(true);
|
||||||
|
EdgeEffect mEdgeGlowTop = (EdgeEffect) field.get(listView);
|
||||||
|
if (mEdgeGlowTop != null) {
|
||||||
|
mEdgeGlowTop.setColor(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
field = AbsListView.class.getDeclaredField("mEdgeGlowBottom");
|
||||||
|
field.setAccessible(true);
|
||||||
|
EdgeEffect mEdgeGlowBottom = (EdgeEffect) field.get(listView);
|
||||||
|
if (mEdgeGlowBottom != null) {
|
||||||
|
mEdgeGlowBottom.setColor(color);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
FileLog.e("tmessages", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void clearDrawableAnimation(View view) {
|
||||||
|
if (Build.VERSION.SDK_INT < 21 || view == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Drawable drawable = null;
|
||||||
|
if (view instanceof ListView) {
|
||||||
|
drawable = ((ListView) view).getSelector();
|
||||||
|
if (drawable != null) {
|
||||||
|
drawable.setState(StateSet.NOTHING);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
drawable = view.getBackground();
|
||||||
|
if (drawable != null) {
|
||||||
|
drawable.setState(StateSet.NOTHING);
|
||||||
|
drawable.jumpToCurrentState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Spannable replaceBold(String str) {
|
||||||
|
int start;
|
||||||
|
ArrayList<Integer> bolds = new ArrayList<Integer>();
|
||||||
|
while ((start = str.indexOf("<b>")) != -1) {
|
||||||
|
int end = str.indexOf("</b>") - 3;
|
||||||
|
str = str.replaceFirst("<b>", "").replaceFirst("</b>", "");
|
||||||
|
bolds.add(start);
|
||||||
|
bolds.add(end);
|
||||||
|
}
|
||||||
|
SpannableStringBuilder stringBuilder = new SpannableStringBuilder(str);
|
||||||
|
for (int a = 0; a < bolds.size() / 2; a++) {
|
||||||
|
TypefaceSpan span = new TypefaceSpan(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
|
||||||
|
stringBuilder.setSpan(span, bolds.get(a * 2), bolds.get(a * 2 + 1), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
|
||||||
|
}
|
||||||
|
return stringBuilder;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,11 +12,11 @@ import android.content.BroadcastReceiver;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
|
||||||
import org.telegram.ui.ApplicationLoader;
|
import org.telegram.messenger.ApplicationLoader;
|
||||||
|
|
||||||
public class AppStartReceiver extends BroadcastReceiver {
|
public class AppStartReceiver extends BroadcastReceiver {
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
AndroidUtilities.RunOnUIThread(new Runnable() {
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
ApplicationLoader.startPushService();
|
ApplicationLoader.startPushService();
|
||||||
|
@ -10,9 +10,11 @@ package org.telegram.android;
|
|||||||
|
|
||||||
import android.accounts.Account;
|
import android.accounts.Account;
|
||||||
import android.accounts.AccountManager;
|
import android.accounts.AccountManager;
|
||||||
|
import android.app.Activity;
|
||||||
import android.content.ContentProviderOperation;
|
import android.content.ContentProviderOperation;
|
||||||
import android.content.ContentProviderResult;
|
import android.content.ContentProviderResult;
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.provider.BaseColumns;
|
import android.provider.BaseColumns;
|
||||||
@ -29,15 +31,17 @@ import org.telegram.messenger.TLObject;
|
|||||||
import org.telegram.messenger.TLRPC;
|
import org.telegram.messenger.TLRPC;
|
||||||
import org.telegram.messenger.UserConfig;
|
import org.telegram.messenger.UserConfig;
|
||||||
import org.telegram.messenger.Utilities;
|
import org.telegram.messenger.Utilities;
|
||||||
import org.telegram.ui.ApplicationLoader;
|
import org.telegram.messenger.ApplicationLoader;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.Locale;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
public class ContactsController {
|
public class ContactsController {
|
||||||
|
|
||||||
private Account currentAccount;
|
private Account currentAccount;
|
||||||
private boolean loadingContacts = false;
|
private boolean loadingContacts = false;
|
||||||
private static final Object loadContactsSync = new Object();
|
private static final Object loadContactsSync = new Object();
|
||||||
@ -48,6 +52,13 @@ public class ContactsController {
|
|||||||
private boolean contactsBookLoaded = false;
|
private boolean contactsBookLoaded = false;
|
||||||
private String lastContactsVersions = "";
|
private String lastContactsVersions = "";
|
||||||
private ArrayList<Integer> delayedContactsUpdate = new ArrayList<Integer>();
|
private ArrayList<Integer> delayedContactsUpdate = new ArrayList<Integer>();
|
||||||
|
private String inviteText;
|
||||||
|
private boolean updatingInviteText = false;
|
||||||
|
|
||||||
|
private int loadingDeleteInfo = 0;
|
||||||
|
private int deleteAccountTTL;
|
||||||
|
private int loadingLastSeenInfo = 0;
|
||||||
|
private ArrayList<TLRPC.PrivacyRule> privacyRules = null;
|
||||||
|
|
||||||
public static class Contact {
|
public static class Contact {
|
||||||
public int id;
|
public int id;
|
||||||
@ -75,8 +86,7 @@ public class ContactsController {
|
|||||||
|
|
||||||
public HashMap<Integer, Contact> contactsBook = new HashMap<Integer, Contact>();
|
public HashMap<Integer, Contact> contactsBook = new HashMap<Integer, Contact>();
|
||||||
public HashMap<String, Contact> contactsBookSPhones = new HashMap<String, Contact>();
|
public HashMap<String, Contact> contactsBookSPhones = new HashMap<String, Contact>();
|
||||||
public HashMap<String, ArrayList<Contact>> contactsSectionsDict = new HashMap<String, ArrayList<Contact>>();
|
public ArrayList<Contact> phoneBookContacts = new ArrayList<Contact>();
|
||||||
public ArrayList<String> sortedContactsSectionsArray = new ArrayList<String>();
|
|
||||||
|
|
||||||
public ArrayList<TLRPC.TL_contact> contacts = new ArrayList<TLRPC.TL_contact>();
|
public ArrayList<TLRPC.TL_contact> contacts = new ArrayList<TLRPC.TL_contact>();
|
||||||
public SparseArray<TLRPC.TL_contact> contactsDict = new SparseArray<TLRPC.TL_contact>();
|
public SparseArray<TLRPC.TL_contact> contactsDict = new SparseArray<TLRPC.TL_contact>();
|
||||||
@ -99,11 +109,17 @@ public class ContactsController {
|
|||||||
return localInstance;
|
return localInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ContactsController() {
|
||||||
|
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE);
|
||||||
|
if (preferences.getBoolean("needGetStatuses", false)) {
|
||||||
|
reloadContactsStatuses();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void cleanup() {
|
public void cleanup() {
|
||||||
contactsBook.clear();
|
contactsBook.clear();
|
||||||
contactsBookSPhones.clear();
|
contactsBookSPhones.clear();
|
||||||
contactsSectionsDict.clear();
|
phoneBookContacts.clear();
|
||||||
sortedContactsSectionsArray.clear();
|
|
||||||
contacts.clear();
|
contacts.clear();
|
||||||
contactsDict.clear();
|
contactsDict.clear();
|
||||||
usersSectionsDict.clear();
|
usersSectionsDict.clear();
|
||||||
@ -116,6 +132,49 @@ public class ContactsController {
|
|||||||
contactsLoaded = false;
|
contactsLoaded = false;
|
||||||
contactsBookLoaded = false;
|
contactsBookLoaded = false;
|
||||||
lastContactsVersions = "";
|
lastContactsVersions = "";
|
||||||
|
loadingDeleteInfo = 0;
|
||||||
|
deleteAccountTTL = 0;
|
||||||
|
loadingLastSeenInfo = 0;
|
||||||
|
privacyRules = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void checkInviteText() {
|
||||||
|
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE);
|
||||||
|
inviteText = preferences.getString("invitetext", null);
|
||||||
|
int time = preferences.getInt("invitetexttime", 0);
|
||||||
|
if (!updatingInviteText && (inviteText == null || time + 86400 < (int)(System.currentTimeMillis() / 1000))) {
|
||||||
|
updatingInviteText = true;
|
||||||
|
TLRPC.TL_help_getInviteText req = new TLRPC.TL_help_getInviteText();
|
||||||
|
req.lang_code = LocaleController.getLocaleString(Locale.getDefault());
|
||||||
|
if (req.lang_code == null || req.lang_code.length() == 0) {
|
||||||
|
req.lang_code = "en";
|
||||||
|
}
|
||||||
|
ConnectionsManager.getInstance().performRpc(req, new RPCRequest.RPCRequestDelegate() {
|
||||||
|
@Override
|
||||||
|
public void run(TLObject response, TLRPC.TL_error error) {
|
||||||
|
if (error == null) {
|
||||||
|
final TLRPC.TL_help_inviteText res = (TLRPC.TL_help_inviteText)response;
|
||||||
|
if (res.message.length() != 0) {
|
||||||
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
updatingInviteText = false;
|
||||||
|
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE);
|
||||||
|
SharedPreferences.Editor editor = preferences.edit();
|
||||||
|
editor.putString("invitetext", res.message);
|
||||||
|
editor.putInt("invitetexttime", (int) (System.currentTimeMillis() / 1000));
|
||||||
|
editor.commit();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, true, RPCRequest.RPCRequestClassGeneric | RPCRequest.RPCRequestClassFailOnServerErrors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getInviteText() {
|
||||||
|
return inviteText != null ? inviteText : LocaleController.getString("InviteText", R.string.InviteText);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void checkAppAccount() {
|
public void checkAppAccount() {
|
||||||
@ -419,7 +478,7 @@ public class ContactsController {
|
|||||||
FileLog.e("tmessages", "detected account deletion!");
|
FileLog.e("tmessages", "detected account deletion!");
|
||||||
currentAccount = new Account(UserConfig.getCurrentUser().phone, "org.telegram.account");
|
currentAccount = new Account(UserConfig.getCurrentUser().phone, "org.telegram.account");
|
||||||
am.addAccountExplicitly(currentAccount, "", null);
|
am.addAccountExplicitly(currentAccount, "", null);
|
||||||
AndroidUtilities.RunOnUIThread(new Runnable() {
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
performWriteContactsToPhoneBook();
|
performWriteContactsToPhoneBook();
|
||||||
@ -546,7 +605,7 @@ public class ContactsController {
|
|||||||
MessagesStorage.getInstance().putCachedPhoneBook(contactsMap);
|
MessagesStorage.getInstance().putCachedPhoneBook(contactsMap);
|
||||||
}
|
}
|
||||||
if (!disableDeletion && !contactHashMap.isEmpty()) {
|
if (!disableDeletion && !contactHashMap.isEmpty()) {
|
||||||
AndroidUtilities.RunOnUIThread(new Runnable() {
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (BuildVars.DEBUG_VERSION) {
|
if (BuildVars.DEBUG_VERSION) {
|
||||||
@ -702,7 +761,7 @@ public class ContactsController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
AndroidUtilities.RunOnUIThread(new Runnable() {
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
updateUnregisteredContacts(contacts);
|
updateUnregisteredContacts(contacts);
|
||||||
@ -763,7 +822,7 @@ public class ContactsController {
|
|||||||
applyContactsUpdates(delayedContactsUpdate, null, null, null);
|
applyContactsUpdates(delayedContactsUpdate, null, null, null);
|
||||||
delayedContactsUpdate.clear();
|
delayedContactsUpdate.clear();
|
||||||
}
|
}
|
||||||
AndroidUtilities.RunOnUIThread(new Runnable() {
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
synchronized (loadContactsSync) {
|
synchronized (loadContactsSync) {
|
||||||
@ -784,13 +843,15 @@ public class ContactsController {
|
|||||||
|
|
||||||
public void processLoadedContacts(final ArrayList<TLRPC.TL_contact> contactsArr, final ArrayList<TLRPC.User> usersArr, final int from) {
|
public void processLoadedContacts(final ArrayList<TLRPC.TL_contact> contactsArr, final ArrayList<TLRPC.User> usersArr, final int from) {
|
||||||
//from: 0 - from server, 1 - from db, 2 - from imported contacts
|
//from: 0 - from server, 1 - from db, 2 - from imported contacts
|
||||||
AndroidUtilities.RunOnUIThread(new Runnable() {
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
MessagesController.getInstance().putUsers(usersArr, from == 1);
|
MessagesController.getInstance().putUsers(usersArr, from == 1);
|
||||||
|
|
||||||
final HashMap<Integer, TLRPC.User> usersDict = new HashMap<Integer, TLRPC.User>();
|
final HashMap<Integer, TLRPC.User> usersDict = new HashMap<Integer, TLRPC.User>();
|
||||||
|
|
||||||
|
final boolean isEmpty = contactsArr.isEmpty();
|
||||||
|
|
||||||
if (!contacts.isEmpty()) {
|
if (!contacts.isEmpty()) {
|
||||||
for (int a = 0; a < contactsArr.size(); a++) {
|
for (int a = 0; a < contactsArr.size(); a++) {
|
||||||
TLRPC.TL_contact contact = contactsArr.get(a);
|
TLRPC.TL_contact contact = contactsArr.get(a);
|
||||||
@ -928,7 +989,7 @@ public class ContactsController {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
AndroidUtilities.RunOnUIThread(new Runnable() {
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
contacts = contactsArr;
|
contacts = contactsArr;
|
||||||
@ -944,6 +1005,12 @@ public class ContactsController {
|
|||||||
updateUnregisteredContacts(contactsArr);
|
updateUnregisteredContacts(contactsArr);
|
||||||
|
|
||||||
NotificationCenter.getInstance().postNotificationName(NotificationCenter.contactsDidLoaded);
|
NotificationCenter.getInstance().postNotificationName(NotificationCenter.contactsDidLoaded);
|
||||||
|
|
||||||
|
if (from != 1 && !isEmpty) {
|
||||||
|
saveContactsLoadTime();
|
||||||
|
} else {
|
||||||
|
reloadContactsStatusesMaybe();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -953,7 +1020,7 @@ public class ContactsController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (contactsByPhonesDictFinal != null) {
|
if (contactsByPhonesDictFinal != null) {
|
||||||
AndroidUtilities.RunOnUIThread(new Runnable() {
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
Utilities.globalQueue.postRunnable(new Runnable() {
|
Utilities.globalQueue.postRunnable(new Runnable() {
|
||||||
@ -978,6 +1045,27 @@ public class ContactsController {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void reloadContactsStatusesMaybe() {
|
||||||
|
try {
|
||||||
|
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE);
|
||||||
|
long lastReloadStatusTime = preferences.getLong("lastReloadStatusTime", 0);
|
||||||
|
if (lastReloadStatusTime < System.currentTimeMillis() - 1000 * 60 * 60 * 24) {
|
||||||
|
reloadContactsStatuses();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
FileLog.e("tmessages", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveContactsLoadTime() {
|
||||||
|
try {
|
||||||
|
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE);
|
||||||
|
preferences.edit().putLong("lastReloadStatusTime", System.currentTimeMillis()).commit();
|
||||||
|
} catch (Exception e) {
|
||||||
|
FileLog.e("tmessages", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void updateUnregisteredContacts(final ArrayList<TLRPC.TL_contact> contactsArr) {
|
private void updateUnregisteredContacts(final ArrayList<TLRPC.TL_contact> contactsArr) {
|
||||||
final HashMap<String, TLRPC.TL_contact> contactsPhonesShort = new HashMap<String, TLRPC.TL_contact>();
|
final HashMap<String, TLRPC.TL_contact> contactsPhonesShort = new HashMap<String, TLRPC.TL_contact>();
|
||||||
|
|
||||||
@ -989,8 +1077,7 @@ public class ContactsController {
|
|||||||
contactsPhonesShort.put(user.phone, value);
|
contactsPhonesShort.put(user.phone, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
final HashMap<String, ArrayList<Contact>> sectionsPhoneDict = new HashMap<String, ArrayList<Contact>>();
|
final ArrayList<Contact> sortedPhoneBookContacts = new ArrayList<Contact>();
|
||||||
final ArrayList<String> sortedSectionsPhoneArray = new ArrayList<String>();
|
|
||||||
for (HashMap.Entry<Integer, Contact> pair : contactsBook.entrySet()) {
|
for (HashMap.Entry<Integer, Contact> pair : contactsBook.entrySet()) {
|
||||||
Contact value = pair.getValue();
|
Contact value = pair.getValue();
|
||||||
int id = pair.getKey();
|
int id = pair.getKey();
|
||||||
@ -1007,61 +1094,24 @@ public class ContactsController {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
String key = value.first_name;
|
sortedPhoneBookContacts.add(value);
|
||||||
if (key.length() == 0) {
|
|
||||||
key = value.last_name;
|
|
||||||
}
|
|
||||||
if (key.length() == 0) {
|
|
||||||
key = "#";
|
|
||||||
if (value.phones.size() != 0) {
|
|
||||||
value.first_name = "+" + value.phones.get(0);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
key = key.toUpperCase();
|
|
||||||
}
|
|
||||||
if (key.length() > 1) {
|
|
||||||
key = key.substring(0, 1);
|
|
||||||
}
|
|
||||||
ArrayList<Contact> arr = sectionsPhoneDict.get(key);
|
|
||||||
if (arr == null) {
|
|
||||||
arr = new ArrayList<Contact>();
|
|
||||||
sectionsPhoneDict.put(key, arr);
|
|
||||||
sortedSectionsPhoneArray.add(key);
|
|
||||||
}
|
|
||||||
arr.add(value);
|
|
||||||
}
|
}
|
||||||
for (HashMap.Entry<String, ArrayList<Contact>> entry : sectionsPhoneDict.entrySet()) {
|
Collections.sort(sortedPhoneBookContacts, new Comparator<Contact>() {
|
||||||
Collections.sort(entry.getValue(), new Comparator<Contact>() {
|
|
||||||
@Override
|
|
||||||
public int compare(Contact contact, Contact contact2) {
|
|
||||||
String toComapre1 = contact.first_name;
|
|
||||||
if (toComapre1.length() == 0) {
|
|
||||||
toComapre1 = contact.last_name;
|
|
||||||
}
|
|
||||||
String toComapre2 = contact2.first_name;
|
|
||||||
if (toComapre2.length() == 0) {
|
|
||||||
toComapre2 = contact2.last_name;
|
|
||||||
}
|
|
||||||
return toComapre1.compareTo(toComapre2);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
Collections.sort(sortedSectionsPhoneArray, new Comparator<String>() {
|
|
||||||
@Override
|
@Override
|
||||||
public int compare(String s, String s2) {
|
public int compare(Contact contact, Contact contact2) {
|
||||||
char cv1 = s.charAt(0);
|
String toComapre1 = contact.first_name;
|
||||||
char cv2 = s2.charAt(0);
|
if (toComapre1.length() == 0) {
|
||||||
if (cv1 == '#') {
|
toComapre1 = contact.last_name;
|
||||||
return 1;
|
|
||||||
} else if (cv2 == '#') {
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
return s.compareTo(s2);
|
String toComapre2 = contact2.first_name;
|
||||||
|
if (toComapre2.length() == 0) {
|
||||||
|
toComapre2 = contact2.last_name;
|
||||||
|
}
|
||||||
|
return toComapre1.compareTo(toComapre2);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
contactsSectionsDict = sectionsPhoneDict;
|
phoneBookContacts = sortedPhoneBookContacts;
|
||||||
sortedContactsSectionsArray = sortedSectionsPhoneArray;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void buildContactsSectionsArrays(boolean sort) {
|
private void buildContactsSectionsArrays(boolean sort) {
|
||||||
@ -1272,7 +1322,7 @@ public class ContactsController {
|
|||||||
} else {
|
} else {
|
||||||
final ArrayList<TLRPC.TL_contact> newContacts = newC;
|
final ArrayList<TLRPC.TL_contact> newContacts = newC;
|
||||||
final ArrayList<Integer> contactsToDelete = contactsTD;
|
final ArrayList<Integer> contactsToDelete = contactsTD;
|
||||||
AndroidUtilities.RunOnUIThread(new Runnable() {
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
for (TLRPC.TL_contact contact : newContacts) {
|
for (TLRPC.TL_contact contact : newContacts) {
|
||||||
@ -1477,7 +1527,7 @@ public class ContactsController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AndroidUtilities.RunOnUIThread(new Runnable() {
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
for (TLRPC.User u : res.users) {
|
for (TLRPC.User u : res.users) {
|
||||||
@ -1541,7 +1591,7 @@ public class ContactsController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AndroidUtilities.RunOnUIThread(new Runnable() {
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
boolean remove = false;
|
boolean remove = false;
|
||||||
@ -1564,6 +1614,132 @@ public class ContactsController {
|
|||||||
}, true, RPCRequest.RPCRequestClassGeneric);
|
}, true, RPCRequest.RPCRequestClassGeneric);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void reloadContactsStatuses() {
|
||||||
|
saveContactsLoadTime();
|
||||||
|
MessagesController.getInstance().clearFullUsers();
|
||||||
|
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE);
|
||||||
|
final SharedPreferences.Editor editor = preferences.edit();
|
||||||
|
editor.putBoolean("needGetStatuses", true).commit();
|
||||||
|
TLRPC.TL_contacts_getStatuses req = new TLRPC.TL_contacts_getStatuses();
|
||||||
|
ConnectionsManager.getInstance().performRpc(req, new RPCRequest.RPCRequestDelegate() {
|
||||||
|
@Override
|
||||||
|
public void run(final TLObject response, TLRPC.TL_error error) {
|
||||||
|
if (error == null) {
|
||||||
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
editor.remove("needGetStatuses").commit();
|
||||||
|
TLRPC.Vector vector = (TLRPC.Vector) response;
|
||||||
|
if (!vector.objects.isEmpty()) {
|
||||||
|
ArrayList<TLRPC.User> dbUsersStatus = new ArrayList<TLRPC.User>();
|
||||||
|
for (Object object : vector.objects) {
|
||||||
|
TLRPC.User toDbUser = new TLRPC.User();
|
||||||
|
TLRPC.TL_contactStatus status = (TLRPC.TL_contactStatus) object;
|
||||||
|
|
||||||
|
if (status == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (status.status instanceof TLRPC.TL_userStatusRecently) {
|
||||||
|
status.status.expires = -100;
|
||||||
|
} else if (status.status instanceof TLRPC.TL_userStatusLastWeek) {
|
||||||
|
status.status.expires = -101;
|
||||||
|
} else if (status.status instanceof TLRPC.TL_userStatusLastMonth) {
|
||||||
|
status.status.expires = -102;
|
||||||
|
}
|
||||||
|
|
||||||
|
TLRPC.User user = MessagesController.getInstance().getUser(status.user_id);
|
||||||
|
if (user != null) {
|
||||||
|
user.status = status.status;
|
||||||
|
}
|
||||||
|
toDbUser.status = status.status;
|
||||||
|
dbUsersStatus.add(toDbUser);
|
||||||
|
}
|
||||||
|
MessagesStorage.getInstance().updateUsers(dbUsersStatus, true, true, true);
|
||||||
|
}
|
||||||
|
NotificationCenter.getInstance().postNotificationName(NotificationCenter.updateInterfaces, MessagesController.UPDATE_MASK_STATUS);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void loadPrivacySettings() {
|
||||||
|
if (loadingDeleteInfo == 0) {
|
||||||
|
loadingDeleteInfo = 1;
|
||||||
|
TLRPC.TL_account_getAccountTTL req = new TLRPC.TL_account_getAccountTTL();
|
||||||
|
ConnectionsManager.getInstance().performRpc(req, new RPCRequest.RPCRequestDelegate() {
|
||||||
|
@Override
|
||||||
|
public void run(final TLObject response, final TLRPC.TL_error error) {
|
||||||
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (error == null) {
|
||||||
|
TLRPC.TL_accountDaysTTL ttl = (TLRPC.TL_accountDaysTTL) response;
|
||||||
|
deleteAccountTTL = ttl.days;
|
||||||
|
loadingDeleteInfo = 2;
|
||||||
|
} else {
|
||||||
|
loadingDeleteInfo = 0;
|
||||||
|
}
|
||||||
|
NotificationCenter.getInstance().postNotificationName(NotificationCenter.privacyRulesUpdated);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (loadingLastSeenInfo == 0) {
|
||||||
|
loadingLastSeenInfo = 1;
|
||||||
|
TLRPC.TL_account_getPrivacy req = new TLRPC.TL_account_getPrivacy();
|
||||||
|
req.key = new TLRPC.TL_inputPrivacyKeyStatusTimestamp();
|
||||||
|
ConnectionsManager.getInstance().performRpc(req, new RPCRequest.RPCRequestDelegate() {
|
||||||
|
@Override
|
||||||
|
public void run(final TLObject response, final TLRPC.TL_error error) {
|
||||||
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (error == null) {
|
||||||
|
TLRPC.TL_account_privacyRules rules = (TLRPC.TL_account_privacyRules) response;
|
||||||
|
MessagesController.getInstance().putUsers(rules.users, false);
|
||||||
|
privacyRules = rules.rules;
|
||||||
|
loadingLastSeenInfo = 2;
|
||||||
|
} else {
|
||||||
|
loadingLastSeenInfo = 0;
|
||||||
|
}
|
||||||
|
NotificationCenter.getInstance().postNotificationName(NotificationCenter.privacyRulesUpdated);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
NotificationCenter.getInstance().postNotificationName(NotificationCenter.privacyRulesUpdated);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeleteAccountTTL(int ttl) {
|
||||||
|
deleteAccountTTL = ttl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getDeleteAccountTTL() {
|
||||||
|
return deleteAccountTTL;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getLoadingDeleteInfo() {
|
||||||
|
return loadingDeleteInfo != 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getLoadingLastSeenInfo() {
|
||||||
|
return loadingLastSeenInfo != 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArrayList<TLRPC.PrivacyRule> getPrivacyRules() {
|
||||||
|
return privacyRules;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPrivacyRules(ArrayList<TLRPC.PrivacyRule> rules) {
|
||||||
|
privacyRules = rules;
|
||||||
|
NotificationCenter.getInstance().postNotificationName(NotificationCenter.privacyRulesUpdated);
|
||||||
|
reloadContactsStatuses();
|
||||||
|
}
|
||||||
|
|
||||||
public static String formatName(String firstName, String lastName) {
|
public static String formatName(String firstName, String lastName) {
|
||||||
String result = null;
|
String result = null;
|
||||||
if (LocaleController.nameDisplayOrder == 1) {
|
if (LocaleController.nameDisplayOrder == 1) {
|
||||||
|
@ -13,6 +13,7 @@ import java.io.InputStream;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.BitmapFactory;
|
import android.graphics.BitmapFactory;
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.ColorFilter;
|
import android.graphics.ColorFilter;
|
||||||
@ -28,28 +29,15 @@ import android.widget.TextView;
|
|||||||
|
|
||||||
import org.telegram.messenger.FileLog;
|
import org.telegram.messenger.FileLog;
|
||||||
import org.telegram.messenger.Utilities;
|
import org.telegram.messenger.Utilities;
|
||||||
import org.telegram.ui.ApplicationLoader;
|
import org.telegram.messenger.ApplicationLoader;
|
||||||
|
|
||||||
public class Emoji {
|
public class Emoji {
|
||||||
private static HashMap<Long, DrawableInfo> rects = new HashMap<Long, DrawableInfo>();
|
private static HashMap<Long, DrawableInfo> rects = new HashMap<Long, DrawableInfo>();
|
||||||
private static int drawImgSize, bigImgSize;
|
private static int drawImgSize, bigImgSize;
|
||||||
private static boolean inited = false;
|
private static boolean inited = false;
|
||||||
private static Paint placeholderPaint;
|
private static Paint placeholderPaint;
|
||||||
private static EmojiBitmap emojiBmp[] = new EmojiBitmap[5];
|
private static Bitmap emojiBmp[] = new Bitmap[5];
|
||||||
private static boolean loadingEmoji[] = new boolean[5];
|
private static boolean loadingEmoji[] = new boolean[5];
|
||||||
private static int emojiFullSize;
|
|
||||||
|
|
||||||
private static class EmojiBitmap {
|
|
||||||
public int[] colors;
|
|
||||||
public int width;
|
|
||||||
public int height;
|
|
||||||
|
|
||||||
public EmojiBitmap(int[] colors, int width, int height) {
|
|
||||||
this.colors = colors;
|
|
||||||
this.width = width;
|
|
||||||
this.height = height;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final int[] cols = {
|
private static final int[] cols = {
|
||||||
13, 10, 15, 10, 14
|
13, 10, 15, 10, 14
|
||||||
@ -125,8 +113,8 @@ public class Emoji {
|
|||||||
0x00000000D83CDF8BL, 0x00000000D83CDF89L, 0x00000000D83CDF8AL, 0x00000000D83CDF88L, 0x00000000D83CDF8CL, 0x00000000D83DDD2EL, 0x00000000D83CDFA5L,
|
0x00000000D83CDF8BL, 0x00000000D83CDF89L, 0x00000000D83CDF8AL, 0x00000000D83CDF88L, 0x00000000D83CDF8CL, 0x00000000D83DDD2EL, 0x00000000D83CDFA5L,
|
||||||
0x00000000D83DDCF7L, 0x00000000D83DDCF9L, 0x00000000D83DDCFCL, 0x00000000D83DDCBFL, 0x00000000D83DDCC0L, 0x00000000D83DDCBDL, 0x00000000D83DDCBEL,
|
0x00000000D83DDCF7L, 0x00000000D83DDCF9L, 0x00000000D83DDCFCL, 0x00000000D83DDCBFL, 0x00000000D83DDCC0L, 0x00000000D83DDCBDL, 0x00000000D83DDCBEL,
|
||||||
0x00000000D83DDCBBL, 0x00000000D83DDCF1L, 0x000000000000260EL, 0x00000000D83DDCDEL, 0x00000000D83DDCDFL, 0x00000000D83DDCE0L, 0x00000000D83DDCE1L,
|
0x00000000D83DDCBBL, 0x00000000D83DDCF1L, 0x000000000000260EL, 0x00000000D83DDCDEL, 0x00000000D83DDCDFL, 0x00000000D83DDCE0L, 0x00000000D83DDCE1L,
|
||||||
0x00000000D83DDCFAL, 0x00000000D83DDCFBL, 0x00000000D83DDD0AL, 0x00000000D83DDD09L, 0x00000000D83DDD08L, 0x00000000D83DDD07L, 0x00000000D83DDD14L, 0x00000000D83DDD15L,
|
0x00000000D83DDCFAL, 0x00000000D83DDCFBL, 0x00000000D83DDD0AL, 0x00000000D83DDD09L, 0x00000000D83DDD08L, 0x00000000D83DDD07L, 0x00000000D83DDD14L,
|
||||||
0x00000000D83DDCE2L, 0x00000000D83DDCE3L, 0x00000000000023F3L, 0x000000000000231BL, 0x00000000000023F0L, 0x000000000000231AL,
|
0x00000000D83DDD15L, 0x00000000D83DDCE2L, 0x00000000D83DDCE3L, 0x00000000000023F3L, 0x000000000000231BL, 0x00000000000023F0L, 0x000000000000231AL,
|
||||||
0x00000000D83DDD13L, 0x00000000D83DDD12L, 0x00000000D83DDD0FL, 0x00000000D83DDD10L, 0x00000000D83DDD11L, 0x00000000D83DDD0EL, 0x00000000D83DDCA1L,
|
0x00000000D83DDD13L, 0x00000000D83DDD12L, 0x00000000D83DDD0FL, 0x00000000D83DDD10L, 0x00000000D83DDD11L, 0x00000000D83DDD0EL, 0x00000000D83DDCA1L,
|
||||||
0x00000000D83DDD26L, 0x00000000D83DDD06L, 0x00000000D83DDD05L, 0x00000000D83DDD0CL, 0x00000000D83DDD0BL, 0x00000000D83DDD0DL, 0x00000000D83DDEC1L, 0x00000000D83DDEC0L,
|
0x00000000D83DDD26L, 0x00000000D83DDD06L, 0x00000000D83DDD05L, 0x00000000D83DDD0CL, 0x00000000D83DDD0BL, 0x00000000D83DDD0DL, 0x00000000D83DDEC1L, 0x00000000D83DDEC0L,
|
||||||
0x00000000D83DDEBFL, 0x00000000D83DDEBDL, 0x00000000D83DDD27L, 0x00000000D83DDD29L, 0x00000000D83DDD28L, 0x00000000D83DDEAAL, 0x00000000D83DDEACL,
|
0x00000000D83DDEBFL, 0x00000000D83DDEBDL, 0x00000000D83DDD27L, 0x00000000D83DDD29L, 0x00000000D83DDD28L, 0x00000000D83DDEAAL, 0x00000000D83DDEACL,
|
||||||
@ -170,20 +158,19 @@ public class Emoji {
|
|||||||
0xD83CDDF0D83CDDF7L, 0xD83CDDE9D83CDDEAL, 0xD83CDDE8D83CDDF3L, 0xD83CDDFAD83CDDF8L, 0xD83CDDEBD83CDDF7L, 0xD83CDDEAD83CDDF8L, 0xD83CDDEED83CDDF9L,
|
0xD83CDDF0D83CDDF7L, 0xD83CDDE9D83CDDEAL, 0xD83CDDE8D83CDDF3L, 0xD83CDDFAD83CDDF8L, 0xD83CDDEBD83CDDF7L, 0xD83CDDEAD83CDDF8L, 0xD83CDDEED83CDDF9L,
|
||||||
0xD83CDDF7D83CDDFAL, 0xD83CDDECD83CDDE7L},
|
0xD83CDDF7D83CDDFAL, 0xD83CDDECD83CDDE7L},
|
||||||
new long[]//209
|
new long[]//209
|
||||||
{0x00000000003120E3L, 0x00000000003220E3L, 0x00000000003320E3L, 0x00000000003420E3L, 0x00000000003520E3L, 0x00000000003620E3L, 0x00000000003720E3L, 0x00000000003820E3L,
|
{0x00000000003120E3L, 0x00000000003220E3L, 0x00000000003320E3L, 0x00000000003420E3L, 0x00000000003520E3L, 0x00000000003620E3L, 0x00000000003720E3L,
|
||||||
0x00000000003920E3L, 0x00000000003020E3L, 0x00000000D83DDD1FL, 0x00000000D83DDD22L, 0x00000000002320E3L, 0x00000000D83DDD23L, 0x0000000000002B06L,
|
0x00000000003820E3L, 0x00000000003920E3L, 0x00000000003020E3L, 0x00000000D83DDD1FL, 0x00000000D83DDD22L, 0x00000000002320E3L, 0x00000000D83DDD23L,
|
||||||
0x0000000000002B07L, 0x0000000000002B05L, 0x00000000000027A1L, 0x00000000D83DDD20L, 0x00000000D83DDD21L, 0x00000000D83DDD24L, 0x0000000000002197L,
|
0x0000000000002B06L, 0x0000000000002B07L, 0x0000000000002B05L, 0x00000000000027A1L, 0x00000000D83DDD20L, 0x00000000D83DDD21L, 0x00000000D83DDD24L,
|
||||||
0x0000000000002196L, 0x0000000000002198L, 0x0000000000002199L, 0x0000000000002194L, 0x0000000000002195L, 0x00000000D83DDD04L, 0x00000000000025C0L,
|
0x0000000000002197L, 0x0000000000002196L, 0x0000000000002198L, 0x0000000000002199L, 0x0000000000002194L, 0x0000000000002195L, 0x00000000D83DDD04L,
|
||||||
0x00000000000025B6L, 0x00000000D83DDD3CL, 0x00000000D83DDD3DL, 0x00000000000021A9L, 0x00000000000021AAL, 0x0000000000002139L, 0x00000000000023EAL,
|
0x00000000000025C0L, 0x00000000000025B6L, 0x00000000D83DDD3CL, 0x00000000D83DDD3DL, 0x00000000000021A9L, 0x00000000000021AAL, 0x0000000000002139L,
|
||||||
0x00000000000023E9L, 0x00000000000023EBL, 0x00000000000023ECL, 0x0000000000002935L, 0x0000000000002934L, 0x00000000D83CDD97L, 0x00000000D83DDD00L,
|
0x00000000000023EAL, 0x00000000000023E9L, 0x00000000000023EBL, 0x00000000000023ECL, 0x0000000000002935L, 0x0000000000002934L, 0x00000000D83CDD97L,
|
||||||
0x00000000D83DDD01L, 0x00000000D83DDD02L, 0x00000000D83CDD95L, 0x00000000D83CDD99L, 0x00000000D83CDD92L, 0x00000000D83CDD93L, 0x00000000D83CDD96L,
|
0x00000000D83DDD00L, 0x00000000D83DDD01L, 0x00000000D83DDD02L, 0x00000000D83CDD95L, 0x00000000D83CDD99L, 0x00000000D83CDD92L, 0x00000000D83CDD93L,
|
||||||
0x00000000D83DDCF6L, 0x00000000D83CDFA6L, 0x00000000D83CDE01L, 0x00000000D83CDE2FL, 0x00000000D83CDE33L, 0x00000000D83CDE35L, 0x00000000D83CDE32L,
|
0x00000000D83CDD96L, 0x00000000D83DDCF6L, 0x00000000D83CDFA6L, 0x00000000D83CDE01L, 0x00000000D83CDE2FL, 0x00000000D83CDE33L, 0x00000000D83CDE35L,
|
||||||
0x00000000D83CDE34L, 0x00000000D83CDE50L, 0x00000000D83CDE39L, 0x00000000D83CDE3AL, 0x00000000D83CDE36L, 0x00000000D83CDE1AL,
|
0x00000000D83CDE32L, 0x00000000D83CDE34L, 0x00000000D83CDE50L, 0x00000000D83CDE39L, 0x00000000D83CDE3AL, 0x00000000D83CDE36L, 0x00000000D83CDE1AL,
|
||||||
0x00000000D83DDEBBL, 0x00000000D83DDEB9L, 0x00000000D83DDEBAL, 0x00000000D83DDEBCL, 0x00000000D83DDEBEL, 0x00000000D83DDEB0L, 0x00000000D83DDEAEL,
|
0x00000000D83DDEBBL, 0x00000000D83DDEB9L, 0x00000000D83DDEBAL, 0x00000000D83DDEBCL, 0x00000000D83DDEBEL, 0x00000000D83DDEB0L, 0x00000000D83DDEAEL,
|
||||||
0x00000000D83CDD7FL, 0x000000000000267FL, 0x00000000D83DDEADL, 0x00000000D83CDE37L, 0x00000000D83CDE38L, 0x00000000D83CDE02L, 0x00000000000024C2L,
|
0x00000000D83CDD7FL, 0x000000000000267FL, 0x00000000D83DDEADL, 0x00000000D83CDE37L, 0x00000000D83CDE38L, 0x00000000D83CDE02L, 0x00000000000024C2L,
|
||||||
0x00000000D83DDEC2L, 0x00000000D83DDEC4L, 0x00000000D83DDEC5L, 0x00000000D83DDEC3L,
|
0x00000000D83DDEC2L, 0x00000000D83DDEC4L, 0x00000000D83DDEC5L, 0x00000000D83DDEC3L, 0x00000000D83CDE51L, 0x0000000000003299L, 0x0000000000003297L,
|
||||||
|
0x00000000D83CDD91L, 0x00000000D83CDD98L, 0x00000000D83CDD94L, 0x00000000D83DDEABL,
|
||||||
0x00000000D83CDE51L, 0x0000000000003299L, 0x0000000000003297L, 0x00000000D83CDD91L, 0x00000000D83CDD98L, 0x00000000D83CDD94L, 0x00000000D83DDEABL,
|
|
||||||
0x00000000D83DDD1EL, 0x00000000D83DDCF5L, 0x00000000D83DDEAFL, 0x00000000D83DDEB1L, 0x00000000D83DDEB3L, 0x00000000D83DDEB7L, 0x00000000D83DDEB8L,
|
0x00000000D83DDD1EL, 0x00000000D83DDCF5L, 0x00000000D83DDEAFL, 0x00000000D83DDEB1L, 0x00000000D83DDEB3L, 0x00000000D83DDEB7L, 0x00000000D83DDEB8L,
|
||||||
0x00000000000026D4L, 0x0000000000002733L, 0x0000000000002747L, 0x000000000000274EL, 0x0000000000002705L, 0x0000000000002734L, 0x00000000D83DDC9FL,
|
0x00000000000026D4L, 0x0000000000002733L, 0x0000000000002747L, 0x000000000000274EL, 0x0000000000002705L, 0x0000000000002734L, 0x00000000D83DDC9FL,
|
||||||
0x00000000D83CDD9AL, 0x00000000D83DDCF3L, 0x00000000D83DDCF4L, 0x00000000D83CDD70L, 0x00000000D83CDD71L, 0x00000000D83CDD8EL, 0x00000000D83CDD7EL,
|
0x00000000D83CDD9AL, 0x00000000D83DDCF3L, 0x00000000D83DDCF4L, 0x00000000D83CDD70L, 0x00000000D83CDD71L, 0x00000000D83CDD8EL, 0x00000000D83CDD7EL,
|
||||||
@ -192,7 +179,7 @@ public class Emoji {
|
|||||||
0x0000000000002653L, 0x00000000000026CEL, 0x00000000D83DDD2FL, 0x00000000D83CDFE7L, 0x00000000D83DDCB9L, 0x00000000D83DDCB2L, 0x00000000D83DDCB1L,
|
0x0000000000002653L, 0x00000000000026CEL, 0x00000000D83DDD2FL, 0x00000000D83CDFE7L, 0x00000000D83DDCB9L, 0x00000000D83DDCB2L, 0x00000000D83DDCB1L,
|
||||||
0x00000000000000A9L, 0x00000000000000AEL, 0x0000000000002122L, 0x000000000000303DL, 0x0000000000003030L, 0x00000000D83DDD1DL, 0x00000000D83DDD1AL,
|
0x00000000000000A9L, 0x00000000000000AEL, 0x0000000000002122L, 0x000000000000303DL, 0x0000000000003030L, 0x00000000D83DDD1DL, 0x00000000D83DDD1AL,
|
||||||
0x00000000D83DDD19L, 0x00000000D83DDD1BL, 0x00000000D83DDD1CL, 0x000000000000274CL, 0x0000000000002B55L, 0x0000000000002757L, 0x000000000000203CL,
|
0x00000000D83DDD19L, 0x00000000D83DDD1BL, 0x00000000D83DDD1CL, 0x000000000000274CL, 0x0000000000002B55L, 0x0000000000002757L, 0x000000000000203CL,
|
||||||
0x0000000000002049L, 0x0000000000002753L,
|
0x0000000000002049L, 0x0000000000002753L,
|
||||||
0x0000000000002755L, 0x0000000000002754L, 0x00000000D83DDD03L, 0x00000000D83DDD5BL, 0x00000000D83DDD67L, 0x00000000D83DDD50L, 0x00000000D83DDD5CL,
|
0x0000000000002755L, 0x0000000000002754L, 0x00000000D83DDD03L, 0x00000000D83DDD5BL, 0x00000000D83DDD67L, 0x00000000D83DDD50L, 0x00000000D83DDD5CL,
|
||||||
0x00000000D83DDD51L, 0x00000000D83DDD5DL, 0x00000000D83DDD52L, 0x00000000D83DDD5EL, 0x00000000D83DDD53L, 0x00000000D83DDD5FL, 0x00000000D83DDD54L,
|
0x00000000D83DDD51L, 0x00000000D83DDD5DL, 0x00000000D83DDD52L, 0x00000000D83DDD5EL, 0x00000000D83DDD53L, 0x00000000D83DDD5FL, 0x00000000D83DDD54L,
|
||||||
0x00000000D83DDD60L, 0x00000000D83DDD55L, 0x00000000D83DDD56L, 0x00000000D83DDD57L, 0x00000000D83DDD58L, 0x00000000D83DDD59L, 0x00000000D83DDD5AL,
|
0x00000000D83DDD60L, 0x00000000D83DDD55L, 0x00000000D83DDD56L, 0x00000000D83DDD57L, 0x00000000D83DDD58L, 0x00000000D83DDD59L, 0x00000000D83DDD5AL,
|
||||||
@ -204,6 +191,7 @@ public class Emoji {
|
|||||||
0x00000000D83DDD34L, 0x00000000D83DDD35L, 0x00000000D83DDD3BL, 0x00000000D83DDD36L, 0x00000000D83DDD37L, 0x00000000D83DDD38L, 0x00000000D83DDD39L}};
|
0x00000000D83DDD34L, 0x00000000D83DDD35L, 0x00000000D83DDD3BL, 0x00000000D83DDD36L, 0x00000000D83DDD37L, 0x00000000D83DDD38L, 0x00000000D83DDD39L}};
|
||||||
|
|
||||||
static {
|
static {
|
||||||
|
int emojiFullSize;
|
||||||
if (AndroidUtilities.density <= 1.0f) {
|
if (AndroidUtilities.density <= 1.0f) {
|
||||||
emojiFullSize = 30;
|
emojiFullSize = 30;
|
||||||
} else if (AndroidUtilities.density <= 1.5f) {
|
} else if (AndroidUtilities.density <= 1.5f) {
|
||||||
@ -222,7 +210,7 @@ public class Emoji {
|
|||||||
|
|
||||||
for (int j = 1; j < data.length; j++) {
|
for (int j = 1; j < data.length; j++) {
|
||||||
for (int i = 0; i < data[j].length; i++) {
|
for (int i = 0; i < data[j].length; i++) {
|
||||||
Rect rect = new Rect((i % cols[j - 1]) * emojiFullSize, (i / cols[j - 1]) * emojiFullSize, emojiFullSize, emojiFullSize);
|
Rect rect = new Rect((i % cols[j - 1]) * emojiFullSize, (i / cols[j - 1]) * emojiFullSize, (i % cols[j - 1] + 1) * emojiFullSize, (i / cols[j - 1] + 1) * emojiFullSize);
|
||||||
rects.put(data[j][i], new DrawableInfo(rect, (byte)(j - 1)));
|
rects.put(data[j][i], new DrawableInfo(rect, (byte)(j - 1)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -260,8 +248,10 @@ public class Emoji {
|
|||||||
|
|
||||||
int width = opts.outWidth / imageResize;
|
int width = opts.outWidth / imageResize;
|
||||||
int height = opts.outHeight / imageResize;
|
int height = opts.outHeight / imageResize;
|
||||||
int[] bitmap = new int[width * height];
|
int stride = width * 4;
|
||||||
Utilities.loadBitmap(imageFile.getAbsolutePath(), bitmap, imageResize, 0, width, height);
|
|
||||||
|
final Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
|
||||||
|
Utilities.loadBitmap(imageFile.getAbsolutePath(), bitmap, imageResize, width, height, stride);
|
||||||
|
|
||||||
imageName = String.format(Locale.US, "emoji%.01fx_a_%d.jpg", scale, page);
|
imageName = String.format(Locale.US, "emoji%.01fx_a_%d.jpg", scale, page);
|
||||||
imageFile = ApplicationLoader.applicationContext.getFileStreamPath(imageName);
|
imageFile = ApplicationLoader.applicationContext.getFileStreamPath(imageName);
|
||||||
@ -271,13 +261,12 @@ public class Emoji {
|
|||||||
is.close();
|
is.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
Utilities.loadBitmap(imageFile.getAbsolutePath(), bitmap, imageResize, 0, width, height);
|
Utilities.loadBitmap(imageFile.getAbsolutePath(), bitmap, imageResize, width, height, stride);
|
||||||
|
|
||||||
final EmojiBitmap emojiBitmap = new EmojiBitmap(bitmap, width, height);
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
AndroidUtilities.RunOnUIThread(new Runnable() {
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
emojiBmp[page] = emojiBitmap;
|
emojiBmp[page] = bitmap;
|
||||||
NotificationCenter.getInstance().postNotificationName(NotificationCenter.emojiDidLoaded);
|
NotificationCenter.getInstance().postNotificationName(NotificationCenter.emojiDidLoaded);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -310,7 +299,7 @@ public class Emoji {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Drawable getEmojiDrawable(long code) {
|
public static EmojiDrawable getEmojiDrawable(long code) {
|
||||||
DrawableInfo info = rects.get(code);
|
DrawableInfo info = rects.get(code);
|
||||||
if (info == null) {
|
if (info == null) {
|
||||||
FileLog.e("tmessages", "No emoji drawable for code " + String.format("%016X", code));
|
FileLog.e("tmessages", "No emoji drawable for code " + String.format("%016X", code));
|
||||||
@ -322,7 +311,7 @@ public class Emoji {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static Drawable getEmojiBigDrawable(long code) {
|
public static Drawable getEmojiBigDrawable(long code) {
|
||||||
EmojiDrawable ed = (EmojiDrawable)getEmojiDrawable(code);
|
EmojiDrawable ed = getEmojiDrawable(code);
|
||||||
if (ed == null) {
|
if (ed == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -333,39 +322,44 @@ public class Emoji {
|
|||||||
|
|
||||||
public static class EmojiDrawable extends Drawable {
|
public static class EmojiDrawable extends Drawable {
|
||||||
private DrawableInfo info;
|
private DrawableInfo info;
|
||||||
boolean fullSize = false;
|
private boolean fullSize = false;
|
||||||
private static Paint paint;
|
private static Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.ANTI_ALIAS_FLAG);
|
||||||
|
|
||||||
static {
|
|
||||||
paint = new Paint();
|
|
||||||
paint.setFlags(Paint.FILTER_BITMAP_FLAG | Paint.ANTI_ALIAS_FLAG);
|
|
||||||
}
|
|
||||||
|
|
||||||
public EmojiDrawable(DrawableInfo i) {
|
public EmojiDrawable(DrawableInfo i) {
|
||||||
info = i;
|
info = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public DrawableInfo getDrawableInfo() {
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Rect getDrawRect() {
|
||||||
|
Rect b = copyBounds();
|
||||||
|
int cX = b.centerX(), cY = b.centerY();
|
||||||
|
b.left = cX - (fullSize ? bigImgSize : drawImgSize) / 2;
|
||||||
|
b.right = cX + (fullSize ? bigImgSize : drawImgSize) / 2;
|
||||||
|
b.top = cY - (fullSize ? bigImgSize : drawImgSize) / 2;
|
||||||
|
b.bottom = cY + (fullSize ? bigImgSize : drawImgSize) / 2;
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void draw(Canvas canvas) {
|
public void draw(Canvas canvas) {
|
||||||
EmojiBitmap bitmap = emojiBmp[info.page];
|
if (emojiBmp[info.page] == null) {
|
||||||
if (bitmap == null) {
|
|
||||||
loadEmojiAsync(info.page);
|
loadEmojiAsync(info.page);
|
||||||
canvas.drawRect(getBounds(), placeholderPaint);
|
canvas.drawRect(getBounds(), placeholderPaint);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
float scale = 1;
|
Rect b;
|
||||||
int offset = 0;
|
|
||||||
if (fullSize) {
|
if (fullSize) {
|
||||||
scale = (float) bigImgSize / (float) emojiFullSize;
|
b = getDrawRect();
|
||||||
offset = (getBounds().width() - bigImgSize) / 2;
|
|
||||||
} else {
|
} else {
|
||||||
scale = (float) getBounds().width() / (float) emojiFullSize;
|
b = getBounds();
|
||||||
}
|
}
|
||||||
|
|
||||||
canvas.save();
|
if (!canvas.quickReject(b.left, b.top, b.right, b.bottom, Canvas.EdgeType.AA)) {
|
||||||
canvas.scale(scale, scale);
|
canvas.drawBitmap(emojiBmp[info.page], info.rect, b, paint);
|
||||||
canvas.drawBitmap(bitmap.colors, info.rect.top * bitmap.width + info.rect.left, bitmap.width, offset, offset, info.rect.right, info.rect.bottom, true, paint);
|
}
|
||||||
canvas.restore();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -424,7 +418,7 @@ public class Emoji {
|
|||||||
} else if (buf > 0 && (c & 0xF000) == 0xD000) {
|
} else if (buf > 0 && (c & 0xF000) == 0xD000) {
|
||||||
buf <<= 16;
|
buf <<= 16;
|
||||||
buf |= c;
|
buf |= c;
|
||||||
Drawable d = Emoji.getEmojiDrawable(buf);
|
EmojiDrawable d = Emoji.getEmojiDrawable(buf);
|
||||||
if (d != null) {
|
if (d != null) {
|
||||||
EmojiSpan span = new EmojiSpan(d, DynamicDrawableSpan.ALIGN_BOTTOM, size, fontMetrics);
|
EmojiSpan span = new EmojiSpan(d, DynamicDrawableSpan.ALIGN_BOTTOM, size, fontMetrics);
|
||||||
emojiCount++;
|
emojiCount++;
|
||||||
@ -442,7 +436,7 @@ public class Emoji {
|
|||||||
buf = c2;
|
buf = c2;
|
||||||
buf <<= 16;
|
buf <<= 16;
|
||||||
buf |= c;
|
buf |= c;
|
||||||
Drawable d = Emoji.getEmojiDrawable(buf);
|
EmojiDrawable d = Emoji.getEmojiDrawable(buf);
|
||||||
if (d != null) {
|
if (d != null) {
|
||||||
EmojiSpan span = new EmojiSpan(d, DynamicDrawableSpan.ALIGN_BOTTOM, size, fontMetrics);
|
EmojiSpan span = new EmojiSpan(d, DynamicDrawableSpan.ALIGN_BOTTOM, size, fontMetrics);
|
||||||
emojiCount++;
|
emojiCount++;
|
||||||
@ -452,7 +446,7 @@ public class Emoji {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (inArray(c, emojiChars)) {
|
} else if (inArray(c, emojiChars)) {
|
||||||
Drawable d = Emoji.getEmojiDrawable(c);
|
EmojiDrawable d = Emoji.getEmojiDrawable(c);
|
||||||
if (d != null) {
|
if (d != null) {
|
||||||
EmojiSpan span = new EmojiSpan(d, DynamicDrawableSpan.ALIGN_BOTTOM, size, fontMetrics);
|
EmojiSpan span = new EmojiSpan(d, DynamicDrawableSpan.ALIGN_BOTTOM, size, fontMetrics);
|
||||||
emojiCount++;
|
emojiCount++;
|
||||||
@ -472,9 +466,9 @@ public class Emoji {
|
|||||||
|
|
||||||
public static class EmojiSpan extends ImageSpan {
|
public static class EmojiSpan extends ImageSpan {
|
||||||
private Paint.FontMetricsInt fontMetrics = null;
|
private Paint.FontMetricsInt fontMetrics = null;
|
||||||
int size = AndroidUtilities.dp(20);
|
private int size = AndroidUtilities.dp(20);
|
||||||
|
|
||||||
public EmojiSpan(Drawable d, int verticalAlignment, int s, Paint.FontMetricsInt original) {
|
public EmojiSpan(EmojiDrawable d, int verticalAlignment, int s, Paint.FontMetricsInt original) {
|
||||||
super(d, verticalAlignment);
|
super(d, verticalAlignment);
|
||||||
fontMetrics = original;
|
fontMetrics = original;
|
||||||
if (original != null) {
|
if (original != null) {
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -16,7 +16,7 @@ import android.content.Intent;
|
|||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
import org.telegram.messenger.ConnectionsManager;
|
import org.telegram.messenger.ConnectionsManager;
|
||||||
import org.telegram.messenger.FileLog;
|
import org.telegram.messenger.FileLog;
|
||||||
import org.telegram.ui.ApplicationLoader;
|
import org.telegram.messenger.ApplicationLoader;
|
||||||
|
|
||||||
public class GcmBroadcastReceiver extends BroadcastReceiver {
|
public class GcmBroadcastReceiver extends BroadcastReceiver {
|
||||||
|
|
||||||
@ -27,7 +27,7 @@ public class GcmBroadcastReceiver extends BroadcastReceiver {
|
|||||||
FileLog.d("tmessages", "GCM received intent: " + intent);
|
FileLog.d("tmessages", "GCM received intent: " + intent);
|
||||||
|
|
||||||
if (intent.getAction().equals("com.google.android.c2dm.intent.RECEIVE")) {
|
if (intent.getAction().equals("com.google.android.c2dm.intent.RECEIVE")) {
|
||||||
AndroidUtilities.RunOnUIThread(new Runnable() {
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
ApplicationLoader.postInitApplication();
|
ApplicationLoader.postInitApplication();
|
||||||
|
@ -31,7 +31,7 @@ import org.telegram.messenger.FileLog;
|
|||||||
import org.telegram.messenger.TLRPC;
|
import org.telegram.messenger.TLRPC;
|
||||||
import org.telegram.messenger.UserConfig;
|
import org.telegram.messenger.UserConfig;
|
||||||
import org.telegram.messenger.Utilities;
|
import org.telegram.messenger.Utilities;
|
||||||
import org.telegram.ui.ApplicationLoader;
|
import org.telegram.messenger.ApplicationLoader;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@ -307,7 +307,7 @@ public class ImageLoader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void onPostExecute(final BitmapDrawable bitmapDrawable) {
|
private void onPostExecute(final BitmapDrawable bitmapDrawable) {
|
||||||
AndroidUtilities.RunOnUIThread(new Runnable() {
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (bitmapDrawable != null && memCache.get(cacheImage.key) == null) {
|
if (bitmapDrawable != null && memCache.get(cacheImage.key) == null) {
|
||||||
@ -518,7 +518,7 @@ public class ImageLoader {
|
|||||||
if (lastProgressUpdateTime == 0 || lastProgressUpdateTime < currentTime - 500) {
|
if (lastProgressUpdateTime == 0 || lastProgressUpdateTime < currentTime - 500) {
|
||||||
lastProgressUpdateTime = currentTime;
|
lastProgressUpdateTime = currentTime;
|
||||||
|
|
||||||
AndroidUtilities.RunOnUIThread(new Runnable() {
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
NotificationCenter.getInstance().postNotificationName(NotificationCenter.FileUploadProgressChanged, location, progress, isEncrypted);
|
NotificationCenter.getInstance().postNotificationName(NotificationCenter.FileUploadProgressChanged, location, progress, isEncrypted);
|
||||||
@ -549,7 +549,7 @@ public class ImageLoader {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void fileDidLoaded(final String location, final File finalFile, final File tempFile) {
|
public void fileDidLoaded(final String location, final File finalFile, final File tempFile) {
|
||||||
AndroidUtilities.RunOnUIThread(new Runnable() {
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (location != null) {
|
if (location != null) {
|
||||||
@ -567,7 +567,7 @@ public class ImageLoader {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void fileDidFailedLoad(final String location, final int state) {
|
public void fileDidFailedLoad(final String location, final int state) {
|
||||||
AndroidUtilities.RunOnUIThread(new Runnable() {
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
ImageLoader.this.fileDidFailedLoad(location);
|
ImageLoader.this.fileDidFailedLoad(location);
|
||||||
@ -581,7 +581,7 @@ public class ImageLoader {
|
|||||||
long currentTime = System.currentTimeMillis();
|
long currentTime = System.currentTimeMillis();
|
||||||
if (lastProgressUpdateTime == 0 || lastProgressUpdateTime < currentTime - 500) {
|
if (lastProgressUpdateTime == 0 || lastProgressUpdateTime < currentTime - 500) {
|
||||||
lastProgressUpdateTime = currentTime;
|
lastProgressUpdateTime = currentTime;
|
||||||
AndroidUtilities.RunOnUIThread(new Runnable() {
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
NotificationCenter.getInstance().postNotificationName(NotificationCenter.FileLoadProgressChanged, location, progress);
|
NotificationCenter.getInstance().postNotificationName(NotificationCenter.FileLoadProgressChanged, location, progress);
|
||||||
@ -601,7 +601,7 @@ public class ImageLoader {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
if (Intent.ACTION_MEDIA_UNMOUNTED.equals(intent.getAction())) {
|
if (Intent.ACTION_MEDIA_UNMOUNTED.equals(intent.getAction())) {
|
||||||
AndroidUtilities.RunOnUIThread(r, 1000);
|
AndroidUtilities.runOnUIThread(r, 1000);
|
||||||
} else {
|
} else {
|
||||||
r.run();
|
r.run();
|
||||||
}
|
}
|
||||||
@ -816,7 +816,7 @@ public class ImageLoader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void replaceImageInCache(final String oldKey, final String newKey) {
|
public void replaceImageInCache(final String oldKey, final String newKey) {
|
||||||
AndroidUtilities.RunOnUIThread(new Runnable() {
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
ArrayList<String> arr = memCache.getFilterKeys(oldKey);
|
ArrayList<String> arr = memCache.getFilterKeys(oldKey);
|
||||||
@ -1117,9 +1117,9 @@ public class ImageLoader {
|
|||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static TLRPC.PhotoSize scaleAndSaveImageInternal(Bitmap bitmap, int w, int h, float photoW, float photoH, float scaleFactor, int quality, boolean cache) throws Exception {
|
private static TLRPC.PhotoSize scaleAndSaveImageInternal(Bitmap bitmap, int w, int h, float photoW, float photoH, float scaleFactor, int quality, boolean cache, boolean scaleAnyway) throws Exception {
|
||||||
Bitmap scaledBitmap = null;
|
Bitmap scaledBitmap = null;
|
||||||
if (scaleFactor > 1) {
|
if (scaleFactor > 1 || scaleAnyway) {
|
||||||
scaledBitmap = Bitmap.createScaledBitmap(bitmap, w, h, true);
|
scaledBitmap = Bitmap.createScaledBitmap(bitmap, w, h, true);
|
||||||
} else {
|
} else {
|
||||||
scaledBitmap = bitmap;
|
scaledBitmap = bitmap;
|
||||||
@ -1171,6 +1171,10 @@ public class ImageLoader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static TLRPC.PhotoSize scaleAndSaveImage(Bitmap bitmap, float maxWidth, float maxHeight, int quality, boolean cache) {
|
public static TLRPC.PhotoSize scaleAndSaveImage(Bitmap bitmap, float maxWidth, float maxHeight, int quality, boolean cache) {
|
||||||
|
return scaleAndSaveImage(bitmap, maxWidth, maxHeight, quality, cache, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TLRPC.PhotoSize scaleAndSaveImage(Bitmap bitmap, float maxWidth, float maxHeight, int quality, boolean cache, int minWidth, int minHeight) {
|
||||||
if (bitmap == null) {
|
if (bitmap == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -1179,7 +1183,12 @@ public class ImageLoader {
|
|||||||
if (photoW == 0 || photoH == 0) {
|
if (photoW == 0 || photoH == 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
boolean scaleAnyway = false;
|
||||||
float scaleFactor = Math.max(photoW / maxWidth, photoH / maxHeight);
|
float scaleFactor = Math.max(photoW / maxWidth, photoH / maxHeight);
|
||||||
|
if (scaleFactor < 1 && minWidth != 0 && minHeight != 0) {
|
||||||
|
scaleFactor = Math.max(photoW / minWidth, photoH / minHeight);
|
||||||
|
scaleAnyway = true;
|
||||||
|
}
|
||||||
int w = (int)(photoW / scaleFactor);
|
int w = (int)(photoW / scaleFactor);
|
||||||
int h = (int)(photoH / scaleFactor);
|
int h = (int)(photoH / scaleFactor);
|
||||||
if (h == 0 || w == 0) {
|
if (h == 0 || w == 0) {
|
||||||
@ -1187,13 +1196,13 @@ public class ImageLoader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return scaleAndSaveImageInternal(bitmap, w, h, photoW, photoH, scaleFactor, quality, cache);
|
return scaleAndSaveImageInternal(bitmap, w, h, photoW, photoH, scaleFactor, quality, cache, scaleAnyway);
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
FileLog.e("tmessages", e);
|
FileLog.e("tmessages", e);
|
||||||
ImageLoader.getInstance().clearMemory();
|
ImageLoader.getInstance().clearMemory();
|
||||||
System.gc();
|
System.gc();
|
||||||
try {
|
try {
|
||||||
return scaleAndSaveImageInternal(bitmap, w, h, photoW, photoH, scaleFactor, quality, cache);
|
return scaleAndSaveImageInternal(bitmap, w, h, photoW, photoH, scaleFactor, quality, cache, scaleAnyway);
|
||||||
} catch (Throwable e2) {
|
} catch (Throwable e2) {
|
||||||
FileLog.e("tmessages", e2);
|
FileLog.e("tmessages", e2);
|
||||||
return null;
|
return null;
|
||||||
|
@ -139,7 +139,7 @@ public class ImageReceiver {
|
|||||||
if (roundRadius != 0) {
|
if (roundRadius != 0) {
|
||||||
bitmapShader = new BitmapShader(bitmap.getBitmap(), Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
|
bitmapShader = new BitmapShader(bitmap.getBitmap(), Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
|
||||||
roundPaint.setShader(bitmapShader);
|
roundPaint.setShader(bitmapShader);
|
||||||
bitmapRect.set(0, 0, bitmap.getIntrinsicWidth(), bitmap.getIntrinsicHeight());
|
bitmapRect.set(0, 0, bitmap.getBitmap().getWidth(), bitmap.getBitmap().getHeight());
|
||||||
}
|
}
|
||||||
if (parentView != null) {
|
if (parentView != null) {
|
||||||
parentView.invalidate();
|
parentView.invalidate();
|
||||||
@ -225,11 +225,13 @@ public class ImageReceiver {
|
|||||||
if (bitmapDrawable != null) {
|
if (bitmapDrawable != null) {
|
||||||
if (bitmapShader != null) {
|
if (bitmapShader != null) {
|
||||||
drawRegion.set(imageX, imageY, imageX + imageW, imageY + imageH);
|
drawRegion.set(imageX, imageY, imageX + imageW, imageY + imageH);
|
||||||
roundRect.set(imageX, imageY, imageX + imageW, imageY + imageH);
|
if (isVisible) {
|
||||||
shaderMatrix.reset();
|
roundRect.set(drawRegion);
|
||||||
shaderMatrix.setScale(1.5f, 1.5f);
|
shaderMatrix.reset();
|
||||||
bitmapShader.setLocalMatrix(shaderMatrix);
|
shaderMatrix.setRectToRect(bitmapRect, roundRect, Matrix.ScaleToFit.FILL);
|
||||||
canvas.drawRoundRect(roundRect, roundRadius, roundRadius, roundPaint);
|
bitmapShader.setLocalMatrix(shaderMatrix);
|
||||||
|
canvas.drawRoundRect(roundRect, roundRadius, roundRadius, roundPaint);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
int bitmapW = bitmapDrawable.getIntrinsicWidth();
|
int bitmapW = bitmapDrawable.getIntrinsicWidth();
|
||||||
int bitmapH = bitmapDrawable.getIntrinsicHeight();
|
int bitmapH = bitmapDrawable.getIntrinsicHeight();
|
||||||
@ -412,10 +414,12 @@ public class ImageReceiver {
|
|||||||
public void setRoundRadius(int value) {
|
public void setRoundRadius(int value) {
|
||||||
roundRadius = value;
|
roundRadius = value;
|
||||||
if (roundRadius != 0) {
|
if (roundRadius != 0) {
|
||||||
roundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
if (roundPaint == null) {
|
||||||
roundRect = new RectF();
|
roundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||||
shaderMatrix = new Matrix();
|
roundRect = new RectF();
|
||||||
bitmapRect = new RectF();
|
shaderMatrix = new Matrix();
|
||||||
|
bitmapRect = new RectF();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
roundPaint = null;
|
roundPaint = null;
|
||||||
roundRect = null;
|
roundRect = null;
|
||||||
@ -423,4 +427,8 @@ public class ImageReceiver {
|
|||||||
bitmapRect = null;
|
bitmapRect = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getRoundRadius() {
|
||||||
|
return roundRadius;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,12 +18,13 @@ import android.content.res.Configuration;
|
|||||||
import android.text.format.DateFormat;
|
import android.text.format.DateFormat;
|
||||||
import android.util.Xml;
|
import android.util.Xml;
|
||||||
|
|
||||||
|
import org.telegram.android.time.FastDateFormat;
|
||||||
import org.telegram.messenger.ConnectionsManager;
|
import org.telegram.messenger.ConnectionsManager;
|
||||||
import org.telegram.messenger.FileLog;
|
import org.telegram.messenger.FileLog;
|
||||||
import org.telegram.messenger.R;
|
import org.telegram.messenger.R;
|
||||||
import org.telegram.messenger.TLRPC;
|
import org.telegram.messenger.TLRPC;
|
||||||
import org.telegram.messenger.Utilities;
|
import org.telegram.messenger.Utilities;
|
||||||
import org.telegram.ui.ApplicationLoader;
|
import org.telegram.messenger.ApplicationLoader;
|
||||||
import org.xmlpull.v1.XmlPullParser;
|
import org.xmlpull.v1.XmlPullParser;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@ -781,8 +782,22 @@ public class LocaleController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static String formatUserStatus(TLRPC.User user) {
|
public static String formatUserStatus(TLRPC.User user) {
|
||||||
|
if (user != null && user.status != null && user.status.expires == 0) {
|
||||||
|
if (user.status instanceof TLRPC.TL_userStatusRecently) {
|
||||||
|
user.status.expires = -100;
|
||||||
|
} else if (user.status instanceof TLRPC.TL_userStatusLastWeek) {
|
||||||
|
user.status.expires = -101;
|
||||||
|
} else if (user.status instanceof TLRPC.TL_userStatusLastMonth) {
|
||||||
|
user.status.expires = -102;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (user != null && user.status != null && user.status.expires <= 0) {
|
||||||
|
if (MessagesController.getInstance().onlinePrivacy.containsKey(user.id)) {
|
||||||
|
return getString("Online", R.string.Online);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (user == null || user.status == null || user.status.expires == 0 || user instanceof TLRPC.TL_userDeleted || user instanceof TLRPC.TL_userEmpty) {
|
if (user == null || user.status == null || user.status.expires == 0 || user instanceof TLRPC.TL_userDeleted || user instanceof TLRPC.TL_userEmpty) {
|
||||||
return getString("Offline", R.string.Offline);
|
return getString("ALongTimeAgo", R.string.ALongTimeAgo);
|
||||||
} else {
|
} else {
|
||||||
int currentTime = ConnectionsManager.getInstance().getCurrentTime();
|
int currentTime = ConnectionsManager.getInstance().getCurrentTime();
|
||||||
if (user.status.expires > currentTime) {
|
if (user.status.expires > currentTime) {
|
||||||
@ -790,7 +805,13 @@ public class LocaleController {
|
|||||||
} else {
|
} else {
|
||||||
if (user.status.expires == -1) {
|
if (user.status.expires == -1) {
|
||||||
return getString("Invisible", R.string.Invisible);
|
return getString("Invisible", R.string.Invisible);
|
||||||
} else {
|
} else if (user.status.expires == -100) {
|
||||||
|
return getString("Lately", R.string.Lately);
|
||||||
|
} else if (user.status.expires == -101) {
|
||||||
|
return getString("WithinAWeek", R.string.WithinAWeek);
|
||||||
|
} else if (user.status.expires == -102) {
|
||||||
|
return getString("WithinAMonth", R.string.WithinAMonth);
|
||||||
|
} else {
|
||||||
return formatDateOnline(user.status.expires);
|
return formatDateOnline(user.status.expires);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,9 +38,7 @@ import android.os.Environment;
|
|||||||
import android.os.ParcelFileDescriptor;
|
import android.os.ParcelFileDescriptor;
|
||||||
import android.os.Vibrator;
|
import android.os.Vibrator;
|
||||||
import android.provider.MediaStore;
|
import android.provider.MediaStore;
|
||||||
import android.view.Display;
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.WindowManager;
|
|
||||||
|
|
||||||
import org.telegram.android.video.InputSurface;
|
import org.telegram.android.video.InputSurface;
|
||||||
import org.telegram.android.video.MP4Builder;
|
import org.telegram.android.video.MP4Builder;
|
||||||
@ -54,15 +52,14 @@ import org.telegram.messenger.R;
|
|||||||
import org.telegram.messenger.TLRPC;
|
import org.telegram.messenger.TLRPC;
|
||||||
import org.telegram.messenger.UserConfig;
|
import org.telegram.messenger.UserConfig;
|
||||||
import org.telegram.messenger.Utilities;
|
import org.telegram.messenger.Utilities;
|
||||||
import org.telegram.ui.ApplicationLoader;
|
import org.telegram.messenger.ApplicationLoader;
|
||||||
import org.telegram.ui.Cells.ChatMediaCell;
|
import org.telegram.ui.Cells.ChatMediaCell;
|
||||||
import org.telegram.ui.Views.GifDrawable;
|
import org.telegram.ui.Components.GifDrawable;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.channels.FileChannel;
|
import java.nio.channels.FileChannel;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -273,7 +270,7 @@ public class MediaController implements NotificationCenter.NotificationCenterDel
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
recordQueue.postRunnable(recordRunnable);
|
recordQueue.postRunnable(recordRunnable);
|
||||||
AndroidUtilities.RunOnUIThread(new Runnable() {
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
NotificationCenter.getInstance().postNotificationName(NotificationCenter.recordProgressChanged, System.currentTimeMillis() - recordStartTime);
|
NotificationCenter.getInstance().postNotificationName(NotificationCenter.recordProgressChanged, System.currentTimeMillis() - recordStartTime);
|
||||||
@ -451,7 +448,7 @@ public class MediaController implements NotificationCenter.NotificationCenterDel
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
synchronized (sync) {
|
synchronized (sync) {
|
||||||
AndroidUtilities.RunOnUIThread(new Runnable() {
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (playingMessageObject != null && (audioPlayer != null || audioTrackPlayer != null) && !isPaused) {
|
if (playingMessageObject != null && (audioPlayer != null || audioTrackPlayer != null) && !isPaused) {
|
||||||
@ -739,29 +736,7 @@ public class MediaController implements NotificationCenter.NotificationCenterDel
|
|||||||
|
|
||||||
public void processMediaObserver(Uri uri) {
|
public void processMediaObserver(Uri uri) {
|
||||||
try {
|
try {
|
||||||
int width = 0;
|
Point size = AndroidUtilities.getRealScreenSize();
|
||||||
int height = 0;
|
|
||||||
|
|
||||||
try {
|
|
||||||
WindowManager windowManager = (WindowManager) ApplicationLoader.applicationContext.getSystemService(Context.WINDOW_SERVICE);
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
|
||||||
Point size = new Point();
|
|
||||||
windowManager.getDefaultDisplay().getRealSize(size);
|
|
||||||
width = size.x;
|
|
||||||
height = size.y;
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
Method mGetRawW = Display.class.getMethod("getRawWidth");
|
|
||||||
Method mGetRawH = Display.class.getMethod("getRawHeight");
|
|
||||||
width = (Integer) mGetRawW.invoke(windowManager.getDefaultDisplay());
|
|
||||||
height = (Integer) mGetRawH.invoke(windowManager.getDefaultDisplay());
|
|
||||||
} catch (Exception e) {
|
|
||||||
FileLog.e("tmessages", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
FileLog.e("tmessages", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
Cursor cursor = ApplicationLoader.applicationContext.getContentResolver().query(uri, mediaProjections, null, null, "date_added DESC LIMIT 1");
|
Cursor cursor = ApplicationLoader.applicationContext.getContentResolver().query(uri, mediaProjections, null, null, "date_added DESC LIMIT 1");
|
||||||
final ArrayList<Long> screenshotDates = new ArrayList<Long>();
|
final ArrayList<Long> screenshotDates = new ArrayList<Long>();
|
||||||
@ -791,7 +766,7 @@ public class MediaController implements NotificationCenter.NotificationCenterDel
|
|||||||
photoW = bmOptions.outWidth;
|
photoW = bmOptions.outWidth;
|
||||||
photoH = bmOptions.outHeight;
|
photoH = bmOptions.outHeight;
|
||||||
}
|
}
|
||||||
if (photoW <= 0 || photoH <= 0 || (photoW == width && photoH == height || photoH == width && photoW == height)) {
|
if (photoW <= 0 || photoH <= 0 || (photoW == size.x && photoH == size.y || photoH == size.x && photoW == size.y)) {
|
||||||
screenshotDates.add(date);
|
screenshotDates.add(date);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@ -802,7 +777,7 @@ public class MediaController implements NotificationCenter.NotificationCenterDel
|
|||||||
cursor.close();
|
cursor.close();
|
||||||
}
|
}
|
||||||
if (!screenshotDates.isEmpty()) {
|
if (!screenshotDates.isEmpty()) {
|
||||||
AndroidUtilities.RunOnUIThread(new Runnable() {
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
NotificationCenter.getInstance().postNotificationName(NotificationCenter.screenshotTook);
|
NotificationCenter.getInstance().postNotificationName(NotificationCenter.screenshotTook);
|
||||||
@ -834,7 +809,7 @@ public class MediaController implements NotificationCenter.NotificationCenterDel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (send) {
|
if (send) {
|
||||||
SendMessagesHelper.getInstance().sendScreenshotMessage(lastSecretChat, lastSecretChatVisibleMessages, null);
|
SecretChatHelper.getInstance().sendScreenshotMessage(lastSecretChat, lastSecretChatVisibleMessages, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1060,7 +1035,7 @@ public class MediaController implements NotificationCenter.NotificationCenterDel
|
|||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
final long pcm = buffer.pcmOffset;
|
final long pcm = buffer.pcmOffset;
|
||||||
final int marker = buffer.finished == 1 ? buffer.size : -1;
|
final int marker = buffer.finished == 1 ? buffer.size : -1;
|
||||||
AndroidUtilities.RunOnUIThread(new Runnable() {
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
lastPlayPcm = pcm;
|
lastPlayPcm = pcm;
|
||||||
@ -1149,7 +1124,7 @@ public class MediaController implements NotificationCenter.NotificationCenterDel
|
|||||||
freePlayerBuffers.addAll(usedPlayerBuffers);
|
freePlayerBuffers.addAll(usedPlayerBuffers);
|
||||||
usedPlayerBuffers.clear();
|
usedPlayerBuffers.clear();
|
||||||
}
|
}
|
||||||
AndroidUtilities.RunOnUIThread(new Runnable() {
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (!isPaused) {
|
if (!isPaused) {
|
||||||
@ -1404,7 +1379,7 @@ public class MediaController implements NotificationCenter.NotificationCenterDel
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (audioRecorder != null) {
|
if (audioRecorder != null) {
|
||||||
AndroidUtilities.RunOnUIThread(new Runnable() {
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
NotificationCenter.getInstance().postNotificationName(NotificationCenter.recordStartError);
|
NotificationCenter.getInstance().postNotificationName(NotificationCenter.recordStartError);
|
||||||
@ -1425,7 +1400,7 @@ public class MediaController implements NotificationCenter.NotificationCenterDel
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
if (startRecord(recordingAudioFile.getAbsolutePath()) == 0) {
|
if (startRecord(recordingAudioFile.getAbsolutePath()) == 0) {
|
||||||
AndroidUtilities.RunOnUIThread(new Runnable() {
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
NotificationCenter.getInstance().postNotificationName(NotificationCenter.recordStartError);
|
NotificationCenter.getInstance().postNotificationName(NotificationCenter.recordStartError);
|
||||||
@ -1453,7 +1428,7 @@ public class MediaController implements NotificationCenter.NotificationCenterDel
|
|||||||
FileLog.e("tmessages", e2);
|
FileLog.e("tmessages", e2);
|
||||||
}
|
}
|
||||||
|
|
||||||
AndroidUtilities.RunOnUIThread(new Runnable() {
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
NotificationCenter.getInstance().postNotificationName(NotificationCenter.recordStartError);
|
NotificationCenter.getInstance().postNotificationName(NotificationCenter.recordStartError);
|
||||||
@ -1463,7 +1438,7 @@ public class MediaController implements NotificationCenter.NotificationCenterDel
|
|||||||
}
|
}
|
||||||
|
|
||||||
recordQueue.postRunnable(recordRunnable);
|
recordQueue.postRunnable(recordRunnable);
|
||||||
AndroidUtilities.RunOnUIThread(new Runnable() {
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
NotificationCenter.getInstance().postNotificationName(NotificationCenter.recordStarted);
|
NotificationCenter.getInstance().postNotificationName(NotificationCenter.recordStarted);
|
||||||
@ -1481,7 +1456,7 @@ public class MediaController implements NotificationCenter.NotificationCenterDel
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
stopRecord();
|
stopRecord();
|
||||||
AndroidUtilities.RunOnUIThread(new Runnable() {
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
audioToSend.date = ConnectionsManager.getInstance().getCurrentTime();
|
audioToSend.date = ConnectionsManager.getInstance().getCurrentTime();
|
||||||
@ -1536,7 +1511,7 @@ public class MediaController implements NotificationCenter.NotificationCenterDel
|
|||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
FileLog.e("tmessages", e);
|
FileLog.e("tmessages", e);
|
||||||
}
|
}
|
||||||
AndroidUtilities.RunOnUIThread(new Runnable() {
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
NotificationCenter.getInstance().postNotificationName(NotificationCenter.recordStopped);
|
NotificationCenter.getInstance().postNotificationName(NotificationCenter.recordStopped);
|
||||||
@ -1567,13 +1542,17 @@ public class MediaController implements NotificationCenter.NotificationCenterDel
|
|||||||
if (sourceFile.exists()) {
|
if (sourceFile.exists()) {
|
||||||
ProgressDialog progressDialog = null;
|
ProgressDialog progressDialog = null;
|
||||||
if (context != null) {
|
if (context != null) {
|
||||||
progressDialog = new ProgressDialog(context);
|
try {
|
||||||
progressDialog.setMessage(LocaleController.getString("Loading", R.string.Loading));
|
progressDialog = new ProgressDialog(context);
|
||||||
progressDialog.setCanceledOnTouchOutside(false);
|
progressDialog.setMessage(LocaleController.getString("Loading", R.string.Loading));
|
||||||
progressDialog.setCancelable(false);
|
progressDialog.setCanceledOnTouchOutside(false);
|
||||||
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
|
progressDialog.setCancelable(false);
|
||||||
progressDialog.setMax(100);
|
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
|
||||||
progressDialog.show();
|
progressDialog.setMax(100);
|
||||||
|
progressDialog.show();
|
||||||
|
} catch (Exception e) {
|
||||||
|
FileLog.e("tmessages", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final ProgressDialog finalProgress = progressDialog;
|
final ProgressDialog finalProgress = progressDialog;
|
||||||
@ -1609,7 +1588,7 @@ public class MediaController implements NotificationCenter.NotificationCenterDel
|
|||||||
if (lastProgress <= System.currentTimeMillis() - 500) {
|
if (lastProgress <= System.currentTimeMillis() - 500) {
|
||||||
lastProgress = System.currentTimeMillis();
|
lastProgress = System.currentTimeMillis();
|
||||||
final int progress = (int) ((float) a / (float) size * 100);
|
final int progress = (int) ((float) a / (float) size * 100);
|
||||||
AndroidUtilities.RunOnUIThread(new Runnable() {
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
@ -1641,7 +1620,7 @@ public class MediaController implements NotificationCenter.NotificationCenterDel
|
|||||||
FileLog.e("tmessages", e);
|
FileLog.e("tmessages", e);
|
||||||
}
|
}
|
||||||
if (finalProgress != null) {
|
if (finalProgress != null) {
|
||||||
AndroidUtilities.RunOnUIThread(new Runnable() {
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
@ -1915,7 +1894,7 @@ public class MediaController implements NotificationCenter.NotificationCenterDel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
final Integer cameraAlbumIdFinal = cameraAlbumId;
|
final Integer cameraAlbumIdFinal = cameraAlbumId;
|
||||||
AndroidUtilities.RunOnUIThread(new Runnable() {
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
NotificationCenter.getInstance().postNotificationName(NotificationCenter.albumsDidLoaded, guid, albumsSorted, cameraAlbumIdFinal);
|
NotificationCenter.getInstance().postNotificationName(NotificationCenter.albumsDidLoaded, guid, albumsSorted, cameraAlbumIdFinal);
|
||||||
@ -2037,7 +2016,7 @@ public class MediaController implements NotificationCenter.NotificationCenterDel
|
|||||||
if (firstWrite) {
|
if (firstWrite) {
|
||||||
videoConvertFirstWrite = false;
|
videoConvertFirstWrite = false;
|
||||||
}
|
}
|
||||||
AndroidUtilities.RunOnUIThread(new Runnable() {
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (error) {
|
if (error) {
|
||||||
|
@ -25,7 +25,7 @@ import org.telegram.messenger.FileLog;
|
|||||||
import org.telegram.messenger.TLRPC;
|
import org.telegram.messenger.TLRPC;
|
||||||
import org.telegram.messenger.R;
|
import org.telegram.messenger.R;
|
||||||
import org.telegram.messenger.UserConfig;
|
import org.telegram.messenger.UserConfig;
|
||||||
import org.telegram.ui.Views.URLSpanNoUnderline;
|
import org.telegram.ui.Components.URLSpanNoUnderline;
|
||||||
|
|
||||||
import java.util.AbstractMap;
|
import java.util.AbstractMap;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -345,7 +345,9 @@ public class MessageObject {
|
|||||||
int dateMonth = rightNow.get(Calendar.MONTH);
|
int dateMonth = rightNow.get(Calendar.MONTH);
|
||||||
dateKey = String.format("%d_%02d_%02d", dateYear, dateMonth, dateDay);
|
dateKey = String.format("%d_%02d_%02d", dateYear, dateMonth, dateDay);
|
||||||
|
|
||||||
generateLayout();
|
if (preview != 0) {
|
||||||
|
generateLayout();
|
||||||
|
}
|
||||||
generateThumbs(false, preview);
|
generateThumbs(false, preview);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -450,6 +452,60 @@ public class MessageObject {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean containsUrls(String message) {
|
||||||
|
if (message == null || message.length() < 3 || message.length() > 1024 * 20) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean containsSomething = false;
|
||||||
|
|
||||||
|
int length = message.length();
|
||||||
|
|
||||||
|
int digitsInRow = 0;
|
||||||
|
int schemeSequence = 0;
|
||||||
|
int dotSequence = 0;
|
||||||
|
|
||||||
|
char lastChar = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < length; i++) {
|
||||||
|
char c = message.charAt(i);
|
||||||
|
|
||||||
|
if (c >= '0' && c <= '9') {
|
||||||
|
digitsInRow++;
|
||||||
|
if (digitsInRow >= 6) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
schemeSequence = 0;
|
||||||
|
dotSequence = 0;
|
||||||
|
} else if (c == ':') {
|
||||||
|
if (schemeSequence == 0) {
|
||||||
|
schemeSequence = 1;
|
||||||
|
} else {
|
||||||
|
schemeSequence = 0;
|
||||||
|
}
|
||||||
|
} else if (c == '/') {
|
||||||
|
if (schemeSequence == 2) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (schemeSequence == 1) {
|
||||||
|
schemeSequence++;
|
||||||
|
} else {
|
||||||
|
schemeSequence = 0;
|
||||||
|
}
|
||||||
|
} else if (c == '.') {
|
||||||
|
if (dotSequence == 0 && lastChar != ' ') {
|
||||||
|
dotSequence++;
|
||||||
|
} else {
|
||||||
|
dotSequence = 0;
|
||||||
|
}
|
||||||
|
} else if (c != ' ' && lastChar == '.' && dotSequence == 1) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
lastChar = c;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private void generateLayout() {
|
private void generateLayout() {
|
||||||
if (type != 0 || messageOwner.to_id == null || messageText == null || messageText.length() == 0) {
|
if (type != 0 || messageOwner.to_id == null || messageText == null || messageText.length() == 0) {
|
||||||
return;
|
return;
|
||||||
@ -457,11 +513,11 @@ public class MessageObject {
|
|||||||
|
|
||||||
textLayoutBlocks = new ArrayList<TextLayoutBlock>();
|
textLayoutBlocks = new ArrayList<TextLayoutBlock>();
|
||||||
|
|
||||||
if (messageText instanceof Spannable) {
|
if (messageText instanceof Spannable && containsUrls(messageOwner.message)) {
|
||||||
if (messageOwner.message != null && messageOwner.message.contains(".") && (messageOwner.message.contains(".com") || messageOwner.message.contains("http") || messageOwner.message.contains(".ru") || messageOwner.message.contains(".org") || messageOwner.message.contains(".net"))) {
|
if (messageOwner.message.length() < 100) {
|
||||||
Linkify.addLinks((Spannable)messageText, Linkify.WEB_URLS);
|
Linkify.addLinks((Spannable) messageText, Linkify.WEB_URLS | Linkify.PHONE_NUMBERS);
|
||||||
} else if (messageText.length() < 100) {
|
} else {
|
||||||
Linkify.addLinks((Spannable)messageText, Linkify.WEB_URLS | Linkify.EMAIL_ADDRESSES | Linkify.PHONE_NUMBERS);
|
Linkify.addLinks((Spannable) messageText, Linkify.WEB_URLS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -574,10 +630,7 @@ public class MessageObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (lineWidth > maxWidth + 100) {
|
if (lineWidth > maxWidth + 100) {
|
||||||
int start = block.textLayout.getLineStart(n);
|
lineWidth = maxWidth;
|
||||||
int end = block.textLayout.getLineEnd(n);
|
|
||||||
CharSequence text = block.textLayout.getText().subSequence(start, end);
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -10,7 +10,6 @@ package org.telegram.android;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.text.Html;
|
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.SparseArray;
|
import android.util.SparseArray;
|
||||||
|
|
||||||
@ -29,7 +28,7 @@ import org.telegram.messenger.TLObject;
|
|||||||
import org.telegram.messenger.TLRPC;
|
import org.telegram.messenger.TLRPC;
|
||||||
import org.telegram.messenger.UserConfig;
|
import org.telegram.messenger.UserConfig;
|
||||||
import org.telegram.messenger.Utilities;
|
import org.telegram.messenger.Utilities;
|
||||||
import org.telegram.ui.ApplicationLoader;
|
import org.telegram.messenger.ApplicationLoader;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -41,7 +40,7 @@ import java.util.Map;
|
|||||||
import java.util.concurrent.Semaphore;
|
import java.util.concurrent.Semaphore;
|
||||||
|
|
||||||
public class MessagesStorage {
|
public class MessagesStorage {
|
||||||
public DispatchQueue storageQueue = new DispatchQueue("storageQueue");
|
private DispatchQueue storageQueue = new DispatchQueue("storageQueue");
|
||||||
private SQLiteDatabase database;
|
private SQLiteDatabase database;
|
||||||
private File cacheFile;
|
private File cacheFile;
|
||||||
private BuffersStorage buffersStorage = new BuffersStorage(false);
|
private BuffersStorage buffersStorage = new BuffersStorage(false);
|
||||||
@ -77,6 +76,18 @@ public class MessagesStorage {
|
|||||||
openDatabase();
|
openDatabase();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SQLiteDatabase getDatabase() {
|
||||||
|
return database;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DispatchQueue getStorageQueue() {
|
||||||
|
return storageQueue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BuffersStorage getBuffersStorage() {
|
||||||
|
return buffersStorage;
|
||||||
|
}
|
||||||
|
|
||||||
public void openDatabase() {
|
public void openDatabase() {
|
||||||
cacheFile = new File(ApplicationLoader.applicationContext.getFilesDir(), "cache4.db");
|
cacheFile = new File(ApplicationLoader.applicationContext.getFilesDir(), "cache4.db");
|
||||||
|
|
||||||
@ -93,7 +104,7 @@ public class MessagesStorage {
|
|||||||
database.executeFast("CREATE TABLE users(uid INTEGER PRIMARY KEY, name TEXT, status INTEGER, data BLOB)").stepThis().dispose();
|
database.executeFast("CREATE TABLE users(uid INTEGER PRIMARY KEY, name TEXT, status INTEGER, data BLOB)").stepThis().dispose();
|
||||||
database.executeFast("CREATE TABLE messages(mid INTEGER PRIMARY KEY, uid INTEGER, read_state INTEGER, send_state INTEGER, date INTEGER, data BLOB, out INTEGER, ttl INTEGER, media INTEGER)").stepThis().dispose();
|
database.executeFast("CREATE TABLE messages(mid INTEGER PRIMARY KEY, uid INTEGER, read_state INTEGER, send_state INTEGER, date INTEGER, data BLOB, out INTEGER, ttl INTEGER, media INTEGER)").stepThis().dispose();
|
||||||
database.executeFast("CREATE TABLE chats(uid INTEGER PRIMARY KEY, name TEXT, data BLOB)").stepThis().dispose();
|
database.executeFast("CREATE TABLE chats(uid INTEGER PRIMARY KEY, name TEXT, data BLOB)").stepThis().dispose();
|
||||||
database.executeFast("CREATE TABLE enc_chats(uid INTEGER PRIMARY KEY, user INTEGER, name TEXT, data BLOB, g BLOB, authkey BLOB, ttl INTEGER, layer INTEGER, seq_in INTEGER, seq_out INTEGER)").stepThis().dispose();
|
database.executeFast("CREATE TABLE enc_chats(uid INTEGER PRIMARY KEY, user INTEGER, name TEXT, data BLOB, g BLOB, authkey BLOB, ttl INTEGER, layer INTEGER, seq_in INTEGER, seq_out INTEGER, use_count INTEGER, exchange_id INTEGER, key_date INTEGER, fprint INTEGER, fauthkey BLOB, khash BLOB)").stepThis().dispose();
|
||||||
database.executeFast("CREATE TABLE dialogs(did INTEGER PRIMARY KEY, date INTEGER, unread_count INTEGER, last_mid INTEGER)").stepThis().dispose();
|
database.executeFast("CREATE TABLE dialogs(did INTEGER PRIMARY KEY, date INTEGER, unread_count INTEGER, last_mid INTEGER)").stepThis().dispose();
|
||||||
database.executeFast("CREATE TABLE chat_settings(uid INTEGER PRIMARY KEY, participants BLOB)").stepThis().dispose();
|
database.executeFast("CREATE TABLE chat_settings(uid INTEGER PRIMARY KEY, participants BLOB)").stepThis().dispose();
|
||||||
database.executeFast("CREATE TABLE contacts(uid INTEGER PRIMARY KEY, mutual INTEGER)").stepThis().dispose();
|
database.executeFast("CREATE TABLE contacts(uid INTEGER PRIMARY KEY, mutual INTEGER)").stepThis().dispose();
|
||||||
@ -110,6 +121,7 @@ public class MessagesStorage {
|
|||||||
database.executeFast("CREATE TABLE download_queue(uid INTEGER, type INTEGER, date INTEGER, data BLOB, PRIMARY KEY (uid, type));").stepThis().dispose();
|
database.executeFast("CREATE TABLE download_queue(uid INTEGER, type INTEGER, date INTEGER, data BLOB, PRIMARY KEY (uid, type));").stepThis().dispose();
|
||||||
database.executeFast("CREATE TABLE dialog_settings(did INTEGER PRIMARY KEY, flags INTEGER);").stepThis().dispose();
|
database.executeFast("CREATE TABLE dialog_settings(did INTEGER PRIMARY KEY, flags INTEGER);").stepThis().dispose();
|
||||||
database.executeFast("CREATE TABLE messages_seq(mid INTEGER PRIMARY KEY, seq_in INTEGER, seq_out INTEGER);").stepThis().dispose();
|
database.executeFast("CREATE TABLE messages_seq(mid INTEGER PRIMARY KEY, seq_in INTEGER, seq_out INTEGER);").stepThis().dispose();
|
||||||
|
//database.executeFast("CREATE TABLE secret_holes(uid INTEGER, seq_in INTEGER, seq_out INTEGER, data BLOB, PRIMARY KEY (uid, seq_in, seq_out));").stepThis().dispose();
|
||||||
|
|
||||||
//database.executeFast("CREATE TABLE attach_data(uid INTEGER, id INTEGER, data BLOB, PRIMARY KEY (uid, id))").stepThis().dispose();
|
//database.executeFast("CREATE TABLE attach_data(uid INTEGER, id INTEGER, data BLOB, PRIMARY KEY (uid, id))").stepThis().dispose();
|
||||||
|
|
||||||
@ -118,6 +130,9 @@ public class MessagesStorage {
|
|||||||
|
|
||||||
database.executeFast("CREATE TABLE sent_files_v2(uid TEXT, type INTEGER, data BLOB, PRIMARY KEY (uid, type))").stepThis().dispose();
|
database.executeFast("CREATE TABLE sent_files_v2(uid TEXT, type INTEGER, data BLOB, PRIMARY KEY (uid, type))").stepThis().dispose();
|
||||||
|
|
||||||
|
//database.executeFast("CREATE TABLE messages_holes(uid INTEGER, start INTEGER, end INTEGER, PRIMARY KEY(uid, start));").stepThis().dispose();
|
||||||
|
//database.executeFast("CREATE INDEX IF NOT EXISTS type_uid_end_messages_holes ON messages_holes(uid, end);").stepThis().dispose();
|
||||||
|
|
||||||
database.executeFast("CREATE INDEX IF NOT EXISTS type_date_idx_download_queue ON download_queue(type, date);").stepThis().dispose();
|
database.executeFast("CREATE INDEX IF NOT EXISTS type_date_idx_download_queue ON download_queue(type, date);").stepThis().dispose();
|
||||||
|
|
||||||
database.executeFast("CREATE INDEX IF NOT EXISTS mid_idx_randoms ON randoms(mid);").stepThis().dispose();
|
database.executeFast("CREATE INDEX IF NOT EXISTS mid_idx_randoms ON randoms(mid);").stepThis().dispose();
|
||||||
@ -141,7 +156,7 @@ public class MessagesStorage {
|
|||||||
|
|
||||||
database.executeFast("CREATE INDEX IF NOT EXISTS seq_idx_messages_seq ON messages_seq(seq_in, seq_out);").stepThis().dispose();
|
database.executeFast("CREATE INDEX IF NOT EXISTS seq_idx_messages_seq ON messages_seq(seq_in, seq_out);").stepThis().dispose();
|
||||||
|
|
||||||
database.executeFast("PRAGMA user_version = 7").stepThis().dispose();
|
database.executeFast("PRAGMA user_version = 10").stepThis().dispose();
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
SQLiteCursor cursor = database.queryFinalized("SELECT seq, pts, date, qts, lsv, sg, pbytes FROM params WHERE id = 1");
|
SQLiteCursor cursor = database.queryFinalized("SELECT seq, pts, date, qts, lsv, sg, pbytes FROM params WHERE id = 1");
|
||||||
@ -173,7 +188,7 @@ public class MessagesStorage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int version = database.executeInt("PRAGMA user_version");
|
int version = database.executeInt("PRAGMA user_version");
|
||||||
if (version < 7) {
|
if (version < 10) {
|
||||||
updateDbToLastVersion(version);
|
updateDbToLastVersion(version);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -303,6 +318,27 @@ public class MessagesStorage {
|
|||||||
database.executeFast("PRAGMA user_version = 7").stepThis().dispose();
|
database.executeFast("PRAGMA user_version = 7").stepThis().dispose();
|
||||||
version = 7;
|
version = 7;
|
||||||
}
|
}
|
||||||
|
/*if (version == 7 && version < 8) {
|
||||||
|
database.executeFast("CREATE TABLE IF NOT EXISTS secret_holes(uid INTEGER, seq_in INTEGER, seq_out INTEGER, data BLOB, PRIMARY KEY (uid, seq_in, seq_out));").stepThis().dispose();
|
||||||
|
database.executeFast("PRAGMA user_version = 8").stepThis().dispose();
|
||||||
|
version = 8;
|
||||||
|
}*/
|
||||||
|
/*if ((version == 7 || version == 8) && version < 9) {
|
||||||
|
database.executeFast("CREATE TABLE IF NOT EXISTS messages_holes(uid INTEGER, start INTEGER, end INTEGER, PRIMARY KEY(uid, start));").stepThis().dispose();
|
||||||
|
database.executeFast("CREATE INDEX IF NOT EXISTS type_uid_end_messages_holes ON messages_holes(uid, end);").stepThis().dispose();
|
||||||
|
database.executeFast("PRAGMA user_version = 9").stepThis().dispose();
|
||||||
|
version = 9;
|
||||||
|
}*/
|
||||||
|
if ((version == 7 || version == 8 || version == 9) && version < 10) {
|
||||||
|
database.executeFast("ALTER TABLE enc_chats ADD COLUMN use_count INTEGER default 0").stepThis().dispose();
|
||||||
|
database.executeFast("ALTER TABLE enc_chats ADD COLUMN exchange_id INTEGER default 0").stepThis().dispose();
|
||||||
|
database.executeFast("ALTER TABLE enc_chats ADD COLUMN key_date INTEGER default 0").stepThis().dispose();
|
||||||
|
database.executeFast("ALTER TABLE enc_chats ADD COLUMN fprint INTEGER default 0").stepThis().dispose();
|
||||||
|
database.executeFast("ALTER TABLE enc_chats ADD COLUMN fauthkey BLOB default NULL").stepThis().dispose();
|
||||||
|
database.executeFast("ALTER TABLE enc_chats ADD COLUMN khash BLOB default NULL").stepThis().dispose();
|
||||||
|
database.executeFast("PRAGMA user_version = 10").stepThis().dispose();
|
||||||
|
version = 10;
|
||||||
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
FileLog.e("tmessages", e);
|
FileLog.e("tmessages", e);
|
||||||
}
|
}
|
||||||
@ -511,7 +547,7 @@ public class MessagesStorage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Collections.reverse(messages);
|
Collections.reverse(messages);
|
||||||
AndroidUtilities.RunOnUIThread(new Runnable() {
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
NotificationsController.getInstance().processLoadedUnreadMessages(pushDialogs, messages, users, chats, encryptedChats);
|
NotificationsController.getInstance().processLoadedUnreadMessages(pushDialogs, messages, users, chats, encryptedChats);
|
||||||
@ -665,6 +701,7 @@ public class MessagesStorage {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
database.executeFast("DELETE FROM enc_chats WHERE uid = " + high_id).stepThis().dispose();
|
database.executeFast("DELETE FROM enc_chats WHERE uid = " + high_id).stepThis().dispose();
|
||||||
|
//database.executeFast("DELETE FROM secret_holes WHERE uid = " + high_id).stepThis().dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
database.executeFast("UPDATE dialogs SET unread_count = 0 WHERE did = " + did).stepThis().dispose();
|
database.executeFast("UPDATE dialogs SET unread_count = 0 WHERE did = " + did).stepThis().dispose();
|
||||||
@ -1016,7 +1053,7 @@ public class MessagesStorage {
|
|||||||
info.version = version;
|
info.version = version;
|
||||||
|
|
||||||
final TLRPC.ChatParticipants finalInfo = info;
|
final TLRPC.ChatParticipants finalInfo = info;
|
||||||
AndroidUtilities.RunOnUIThread(new Runnable() {
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
NotificationCenter.getInstance().postNotificationName(NotificationCenter.chatInfoDidLoaded, finalInfo.chat_id, finalInfo);
|
NotificationCenter.getInstance().postNotificationName(NotificationCenter.chatInfoDidLoaded, finalInfo.chat_id, finalInfo);
|
||||||
@ -1145,131 +1182,6 @@ public class MessagesStorage {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void searchDialogs(final Integer token, final String query, final boolean needEncrypted) {
|
|
||||||
storageQueue.postRunnable(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
ArrayList<TLRPC.User> encUsers = new ArrayList<TLRPC.User>();
|
|
||||||
String q = query.trim().toLowerCase();
|
|
||||||
if (q.length() == 0) {
|
|
||||||
NotificationCenter.getInstance().postNotificationName(NotificationCenter.reloadSearchResults, token, new ArrayList<TLObject>(), new ArrayList<CharSequence>(), new ArrayList<CharSequence>());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ArrayList<TLObject> resultArray = new ArrayList<TLObject>();
|
|
||||||
ArrayList<CharSequence> resultArrayNames = new ArrayList<CharSequence>();
|
|
||||||
|
|
||||||
SQLiteCursor cursor = database.queryFinalized("SELECT u.data, u.status, u.name FROM users as u INNER JOIN contacts as c ON u.uid = c.uid");
|
|
||||||
while (cursor.next()) {
|
|
||||||
String name = cursor.stringValue(2);
|
|
||||||
String username = null;
|
|
||||||
int usernamePos = name.lastIndexOf(";;;");
|
|
||||||
if (usernamePos != -1) {
|
|
||||||
username = name.substring(usernamePos + 3);
|
|
||||||
}
|
|
||||||
int found = 0;
|
|
||||||
if (name.startsWith(q) || name.contains(" " + q)) {
|
|
||||||
found = 1;
|
|
||||||
} else if (username != null && username.startsWith(q)) {
|
|
||||||
found = 2;
|
|
||||||
}
|
|
||||||
if (found != 0) {
|
|
||||||
ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0));
|
|
||||||
if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) {
|
|
||||||
TLRPC.User user = (TLRPC.User)TLClassStore.Instance().TLdeserialize(data, data.readInt32());
|
|
||||||
if (user.id != UserConfig.getClientUserId()) {
|
|
||||||
if (user.status != null) {
|
|
||||||
user.status.expires = cursor.intValue(1);
|
|
||||||
}
|
|
||||||
if (found == 1) {
|
|
||||||
resultArrayNames.add(Utilities.generateSearchName(user.first_name, user.last_name, q));
|
|
||||||
} else {
|
|
||||||
resultArrayNames.add(Utilities.generateSearchName("@" + user.username, null, "@" + q));
|
|
||||||
}
|
|
||||||
resultArray.add(user);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
buffersStorage.reuseFreeBuffer(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cursor.dispose();
|
|
||||||
|
|
||||||
if (needEncrypted) {
|
|
||||||
cursor = database.queryFinalized("SELECT q.data, u.name, q.user, q.g, q.authkey, q.ttl, u.data, u.status, q.layer, q.seq_in, q.seq_out FROM enc_chats as q INNER JOIN dialogs as d ON (q.uid << 32) = d.did INNER JOIN users as u ON q.user = u.uid");
|
|
||||||
while (cursor.next()) {
|
|
||||||
String name = cursor.stringValue(1);
|
|
||||||
|
|
||||||
String username = null;
|
|
||||||
int usernamePos = name.lastIndexOf(";;;");
|
|
||||||
if (usernamePos != -1) {
|
|
||||||
username = name.substring(usernamePos + 2);
|
|
||||||
}
|
|
||||||
int found = 0;
|
|
||||||
if (name.startsWith(q) || name.contains(" " + q)) {
|
|
||||||
found = 1;
|
|
||||||
} else if (username != null && username.startsWith(q)) {
|
|
||||||
found = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (found != 0) {
|
|
||||||
ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0));
|
|
||||||
ByteBufferDesc data2 = buffersStorage.getFreeBuffer(cursor.byteArrayLength(6));
|
|
||||||
if (data != null && cursor.byteBufferValue(0, data.buffer) != 0 && cursor.byteBufferValue(6, data2.buffer) != 0) {
|
|
||||||
TLRPC.EncryptedChat chat = (TLRPC.EncryptedChat) TLClassStore.Instance().TLdeserialize(data, data.readInt32());
|
|
||||||
chat.user_id = cursor.intValue(2);
|
|
||||||
chat.a_or_b = cursor.byteArrayValue(3);
|
|
||||||
chat.auth_key = cursor.byteArrayValue(4);
|
|
||||||
chat.ttl = cursor.intValue(5);
|
|
||||||
chat.layer = cursor.intValue(8);
|
|
||||||
chat.seq_in = cursor.intValue(9);
|
|
||||||
chat.seq_out = cursor.intValue(10);
|
|
||||||
|
|
||||||
TLRPC.User user = (TLRPC.User)TLClassStore.Instance().TLdeserialize(data2, data2.readInt32());
|
|
||||||
if (user.status != null) {
|
|
||||||
user.status.expires = cursor.intValue(7);
|
|
||||||
}
|
|
||||||
if (found == 1) {
|
|
||||||
resultArrayNames.add(Html.fromHtml("<font color=\"#00a60e\">" + ContactsController.formatName(user.first_name, user.last_name) + "</font>"));
|
|
||||||
} else {
|
|
||||||
resultArrayNames.add(Utilities.generateSearchName("@" + user.username, null, "@" + q));
|
|
||||||
}
|
|
||||||
resultArray.add(chat);
|
|
||||||
encUsers.add(user);
|
|
||||||
}
|
|
||||||
buffersStorage.reuseFreeBuffer(data);
|
|
||||||
buffersStorage.reuseFreeBuffer(data2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cursor.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
cursor = database.queryFinalized("SELECT data, name FROM chats");
|
|
||||||
while (cursor.next()) {
|
|
||||||
String name = cursor.stringValue(1);
|
|
||||||
String[] args = name.split(" ");
|
|
||||||
if (name.startsWith(q) || name.contains(" " + q)) {
|
|
||||||
ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0));
|
|
||||||
if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) {
|
|
||||||
TLRPC.Chat chat = (TLRPC.Chat) TLClassStore.Instance().TLdeserialize(data, data.readInt32());
|
|
||||||
if (!needEncrypted && chat.id < 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
resultArrayNames.add(Utilities.generateSearchName(chat.title, null, q));
|
|
||||||
resultArray.add(chat);
|
|
||||||
}
|
|
||||||
buffersStorage.reuseFreeBuffer(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cursor.dispose();
|
|
||||||
|
|
||||||
NotificationCenter.getInstance().postNotificationName(NotificationCenter.reloadSearchResults, token, resultArray, resultArrayNames, encUsers);
|
|
||||||
} catch (Exception e) {
|
|
||||||
FileLog.e("tmessages", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void putContacts(final ArrayList<TLRPC.TL_contact> contacts, final boolean deleteAll) {
|
public void putContacts(final ArrayList<TLRPC.TL_contact> contacts, final boolean deleteAll) {
|
||||||
if (contacts.isEmpty()) {
|
if (contacts.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
@ -1427,9 +1339,6 @@ public class MessagesStorage {
|
|||||||
StringBuilder uids = new StringBuilder();
|
StringBuilder uids = new StringBuilder();
|
||||||
while (cursor.next()) {
|
while (cursor.next()) {
|
||||||
int user_id = cursor.intValue(0);
|
int user_id = cursor.intValue(0);
|
||||||
if (user_id == UserConfig.getClientUserId()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
TLRPC.TL_contact contact = new TLRPC.TL_contact();
|
TLRPC.TL_contact contact = new TLRPC.TL_contact();
|
||||||
contact.user_id = user_id;
|
contact.user_id = user_id;
|
||||||
contact.mutual = cursor.intValue(1) == 1;
|
contact.mutual = cursor.intValue(1) == 1;
|
||||||
@ -1713,7 +1622,30 @@ public class MessagesStorage {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void getMessages(final long dialog_id, final int count, final int max_id, final int minDate, final int classGuid, final boolean from_unread, final boolean forward, final Semaphore semaphore) {
|
/*private ArrayList<Range<Integer>> getHoles(long dialog_id) {
|
||||||
|
int lower_id = (int)dialog_id;
|
||||||
|
int high_id = (int)(dialog_id >> 32);
|
||||||
|
|
||||||
|
if (lower_id == 0 || lower_id != 0 && high_id == 1) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
ArrayList<Range<Integer>> holes = null;
|
||||||
|
try {
|
||||||
|
SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT start, end FROM messages_holes WHERE uid = %d", dialog_id));
|
||||||
|
while (cursor.next()) {
|
||||||
|
if (holes == null) {
|
||||||
|
holes = new ArrayList<Range<Integer>>();
|
||||||
|
}
|
||||||
|
holes.add(new Range<Integer>(cursor.intValue(0), cursor.intValue(1)));
|
||||||
|
}
|
||||||
|
cursor.dispose();
|
||||||
|
} catch (Exception e) {
|
||||||
|
FileLog.e("tmessages" , e);
|
||||||
|
}
|
||||||
|
return holes;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
public void getMessages(final long dialog_id, final int count, final int max_id, final int minDate, final int classGuid, final int load_type) {
|
||||||
storageQueue.postRunnable(new Runnable() {
|
storageQueue.postRunnable(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
@ -1722,17 +1654,41 @@ public class MessagesStorage {
|
|||||||
int count_query = count;
|
int count_query = count;
|
||||||
int offset_query = 0;
|
int offset_query = 0;
|
||||||
int min_unread_id = 0;
|
int min_unread_id = 0;
|
||||||
int max_unread_id = 0;
|
int last_message_id = 0;
|
||||||
|
int first_message_id = 0;
|
||||||
int max_unread_date = 0;
|
int max_unread_date = 0;
|
||||||
|
int hole_start = Integer.MAX_VALUE;
|
||||||
|
int hole_end = Integer.MAX_VALUE;
|
||||||
try {
|
try {
|
||||||
ArrayList<Integer> loadedUsers = new ArrayList<Integer>();
|
ArrayList<Integer> loadedUsers = new ArrayList<Integer>();
|
||||||
ArrayList<Integer> fromUser = new ArrayList<Integer>();
|
ArrayList<Integer> fromUser = new ArrayList<Integer>();
|
||||||
|
|
||||||
SQLiteCursor cursor;
|
SQLiteCursor cursor = null;
|
||||||
int lower_id = (int)dialog_id;
|
int lower_id = (int)dialog_id;
|
||||||
|
|
||||||
if (lower_id != 0) {
|
if (lower_id != 0) {
|
||||||
if (forward) {
|
if (load_type == 3) {
|
||||||
|
cursor = database.queryFinalized(String.format(Locale.US, "SELECT max(mid), min(mid) FROM messages WHERE uid = %d AND mid > 0", dialog_id));
|
||||||
|
if (cursor.next()) {
|
||||||
|
last_message_id = cursor.intValue(0);
|
||||||
|
first_message_id = cursor.intValue(1);
|
||||||
|
}
|
||||||
|
cursor.dispose();
|
||||||
|
|
||||||
|
boolean containMessage = false;
|
||||||
|
cursor = database.queryFinalized(String.format(Locale.US, "SELECT mid FROM messages WHERE mid = %d", max_id));
|
||||||
|
if (cursor.next()) {
|
||||||
|
containMessage = true;
|
||||||
|
}
|
||||||
|
cursor.dispose();
|
||||||
|
|
||||||
|
if (containMessage) {
|
||||||
|
cursor = database.queryFinalized(String.format(Locale.US, "SELECT * FROM (SELECT read_state, data, send_state, mid, date FROM messages WHERE uid = %d AND mid <= %d ORDER BY date DESC, mid DESC LIMIT %d) UNION " +
|
||||||
|
"SELECT * FROM (SELECT read_state, data, send_state, mid, date FROM messages WHERE uid = %d AND mid > %d ORDER BY date ASC, mid ASC LIMIT %d)", dialog_id, max_id, count_query / 2, dialog_id, max_id, count_query / 2 - 1));
|
||||||
|
} else {
|
||||||
|
cursor = null;
|
||||||
|
}
|
||||||
|
} else if (load_type == 1) {
|
||||||
cursor = database.queryFinalized(String.format(Locale.US, "SELECT read_state, data, send_state, mid, date FROM messages WHERE uid = %d AND date >= %d AND mid > %d ORDER BY date ASC, mid ASC LIMIT %d", dialog_id, minDate, max_id, count_query));
|
cursor = database.queryFinalized(String.format(Locale.US, "SELECT read_state, data, send_state, mid, date FROM messages WHERE uid = %d AND date >= %d AND mid > %d ORDER BY date ASC, mid ASC LIMIT %d", dialog_id, minDate, max_id, count_query));
|
||||||
} else if (minDate != 0) {
|
} else if (minDate != 0) {
|
||||||
if (max_id != 0) {
|
if (max_id != 0) {
|
||||||
@ -1741,12 +1697,17 @@ public class MessagesStorage {
|
|||||||
cursor = database.queryFinalized(String.format(Locale.US, "SELECT read_state, data, send_state, mid, date FROM messages WHERE uid = %d AND date <= %d ORDER BY date DESC, mid DESC LIMIT %d,%d", dialog_id, minDate, offset_query, count_query));
|
cursor = database.queryFinalized(String.format(Locale.US, "SELECT read_state, data, send_state, mid, date FROM messages WHERE uid = %d AND date <= %d ORDER BY date DESC, mid DESC LIMIT %d,%d", dialog_id, minDate, offset_query, count_query));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (from_unread) {
|
if (load_type == 2) {
|
||||||
cursor = database.queryFinalized(String.format(Locale.US, "SELECT min(mid), max(mid), max(date) FROM messages WHERE uid = %d AND out = 0 AND read_state = 0 AND mid > 0", dialog_id));
|
cursor = database.queryFinalized(String.format(Locale.US, "SELECT max(mid) FROM messages WHERE uid = %d AND mid > 0", dialog_id));
|
||||||
|
if (cursor.next()) {
|
||||||
|
last_message_id = cursor.intValue(0);
|
||||||
|
}
|
||||||
|
cursor.dispose();
|
||||||
|
|
||||||
|
cursor = database.queryFinalized(String.format(Locale.US, "SELECT min(mid), max(date) FROM messages WHERE uid = %d AND out = 0 AND read_state = 0 AND mid > 0", dialog_id));
|
||||||
if (cursor.next()) {
|
if (cursor.next()) {
|
||||||
min_unread_id = cursor.intValue(0);
|
min_unread_id = cursor.intValue(0);
|
||||||
max_unread_id = cursor.intValue(1);
|
max_unread_date = cursor.intValue(1);
|
||||||
max_unread_date = cursor.intValue(2);
|
|
||||||
}
|
}
|
||||||
cursor.dispose();
|
cursor.dispose();
|
||||||
if (min_unread_id != 0) {
|
if (min_unread_id != 0) {
|
||||||
@ -1763,7 +1724,7 @@ public class MessagesStorage {
|
|||||||
if (count_unread < 4) {
|
if (count_unread < 4) {
|
||||||
count_unread = 0;
|
count_unread = 0;
|
||||||
min_unread_id = 0;
|
min_unread_id = 0;
|
||||||
max_unread_id = 0;
|
last_message_id = 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
offset_query = count_unread - count_query;
|
offset_query = count_unread - count_query;
|
||||||
@ -1772,7 +1733,7 @@ public class MessagesStorage {
|
|||||||
cursor = database.queryFinalized(String.format(Locale.US, "SELECT read_state, data, send_state, mid, date FROM messages WHERE uid = %d ORDER BY date DESC, mid DESC LIMIT %d,%d", dialog_id, offset_query, count_query));
|
cursor = database.queryFinalized(String.format(Locale.US, "SELECT read_state, data, send_state, mid, date FROM messages WHERE uid = %d ORDER BY date DESC, mid DESC LIMIT %d,%d", dialog_id, offset_query, count_query));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (forward) {
|
if (load_type == 1) {
|
||||||
cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND m.mid < %d ORDER BY m.mid DESC LIMIT %d", dialog_id, max_id, count_query));
|
cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND m.mid < %d ORDER BY m.mid DESC LIMIT %d", dialog_id, max_id, count_query));
|
||||||
} else if (minDate != 0) {
|
} else if (minDate != 0) {
|
||||||
if (max_id != 0) {
|
if (max_id != 0) {
|
||||||
@ -1781,12 +1742,17 @@ public class MessagesStorage {
|
|||||||
cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND m.date <= %d ORDER BY m.mid ASC LIMIT %d,%d", dialog_id, minDate, offset_query, count_query));
|
cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND m.date <= %d ORDER BY m.mid ASC LIMIT %d,%d", dialog_id, minDate, offset_query, count_query));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (from_unread) {
|
if (load_type == 2) {
|
||||||
cursor = database.queryFinalized(String.format(Locale.US, "SELECT max(mid), min(mid), max(date) FROM messages WHERE uid = %d AND out = 0 AND read_state = 0 AND mid < 0", dialog_id));
|
cursor = database.queryFinalized(String.format(Locale.US, "SELECT min(mid) FROM messages WHERE uid = %d AND mid < 0", dialog_id));
|
||||||
|
if (cursor.next()) {
|
||||||
|
last_message_id = cursor.intValue(0);
|
||||||
|
}
|
||||||
|
cursor.dispose();
|
||||||
|
|
||||||
|
cursor = database.queryFinalized(String.format(Locale.US, "SELECT max(mid), max(date) FROM messages WHERE uid = %d AND out = 0 AND read_state = 0 AND mid < 0", dialog_id));
|
||||||
if (cursor.next()) {
|
if (cursor.next()) {
|
||||||
min_unread_id = cursor.intValue(0);
|
min_unread_id = cursor.intValue(0);
|
||||||
max_unread_id = cursor.intValue(1);
|
max_unread_date = cursor.intValue(1);
|
||||||
max_unread_date = cursor.intValue(2);
|
|
||||||
}
|
}
|
||||||
cursor.dispose();
|
cursor.dispose();
|
||||||
if (min_unread_id != 0) {
|
if (min_unread_id != 0) {
|
||||||
@ -1803,7 +1769,7 @@ public class MessagesStorage {
|
|||||||
if (count_unread < 4) {
|
if (count_unread < 4) {
|
||||||
count_unread = 0;
|
count_unread = 0;
|
||||||
min_unread_id = 0;
|
min_unread_id = 0;
|
||||||
max_unread_id = 0;
|
last_message_id = 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
offset_query = count_unread - count_query;
|
offset_query = count_unread - count_query;
|
||||||
@ -1812,100 +1778,106 @@ public class MessagesStorage {
|
|||||||
cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d ORDER BY m.mid ASC LIMIT %d,%d", dialog_id, offset_query, count_query));
|
cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d ORDER BY m.mid ASC LIMIT %d,%d", dialog_id, offset_query, count_query));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (cursor.next()) {
|
if (cursor != null) {
|
||||||
ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(1));
|
while (cursor.next()) {
|
||||||
if (data != null && cursor.byteBufferValue(1, data.buffer) != 0) {
|
ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(1));
|
||||||
TLRPC.Message message = (TLRPC.Message)TLClassStore.Instance().TLdeserialize(data, data.readInt32());
|
if (data != null && cursor.byteBufferValue(1, data.buffer) != 0) {
|
||||||
MessageObject.setIsUnread(message, cursor.intValue(0) != 1);
|
TLRPC.Message message = (TLRPC.Message) TLClassStore.Instance().TLdeserialize(data, data.readInt32());
|
||||||
message.id = cursor.intValue(3);
|
MessageObject.setIsUnread(message, cursor.intValue(0) != 1);
|
||||||
message.date = cursor.intValue(4);
|
message.id = cursor.intValue(3);
|
||||||
message.dialog_id = dialog_id;
|
message.date = cursor.intValue(4);
|
||||||
res.messages.add(message);
|
message.dialog_id = dialog_id;
|
||||||
fromUser.add(message.from_id);
|
res.messages.add(message);
|
||||||
if (message.action != null && message.action.user_id != 0) {
|
fromUser.add(message.from_id);
|
||||||
fromUser.add(message.action.user_id);
|
if (message.action != null && message.action.user_id != 0) {
|
||||||
}
|
fromUser.add(message.action.user_id);
|
||||||
if (message.media != null && message.media.user_id != 0) {
|
|
||||||
fromUser.add(message.media.user_id);
|
|
||||||
}
|
|
||||||
if (message.media != null && message.media.audio != null && message.media.audio.user_id != 0) {
|
|
||||||
fromUser.add(message.media.audio.user_id);
|
|
||||||
}
|
|
||||||
if (message.fwd_from_id != 0) {
|
|
||||||
fromUser.add(message.fwd_from_id);
|
|
||||||
}
|
|
||||||
message.send_state = cursor.intValue(2);
|
|
||||||
if (!MessageObject.isUnread(message) && lower_id != 0 || message.id > 0) {
|
|
||||||
message.send_state = 0;
|
|
||||||
}
|
|
||||||
if (lower_id == 0 && !cursor.isNull(5)) {
|
|
||||||
message.random_id = cursor.longValue(5);
|
|
||||||
}
|
|
||||||
if ((int)dialog_id == 0 && message.media != null && message.media.photo != null) {
|
|
||||||
try {
|
|
||||||
SQLiteCursor cursor2 = database.queryFinalized(String.format(Locale.US, "SELECT date FROM enc_tasks_v2 WHERE mid = %d", message.id));
|
|
||||||
if (cursor2.next()) {
|
|
||||||
message.destroyTime = cursor2.intValue(0);
|
|
||||||
}
|
|
||||||
cursor2.dispose();
|
|
||||||
} catch (Exception e) {
|
|
||||||
FileLog.e("tmessages", e);
|
|
||||||
}
|
}
|
||||||
|
if (message.media != null && message.media.user_id != 0) {
|
||||||
|
fromUser.add(message.media.user_id);
|
||||||
|
}
|
||||||
|
if (message.media != null && message.media.audio != null && message.media.audio.user_id != 0) {
|
||||||
|
fromUser.add(message.media.audio.user_id);
|
||||||
|
}
|
||||||
|
if (message.fwd_from_id != 0) {
|
||||||
|
fromUser.add(message.fwd_from_id);
|
||||||
|
}
|
||||||
|
message.send_state = cursor.intValue(2);
|
||||||
|
if (!MessageObject.isUnread(message) && lower_id != 0 || message.id > 0) {
|
||||||
|
message.send_state = 0;
|
||||||
|
}
|
||||||
|
if (lower_id == 0 && !cursor.isNull(5)) {
|
||||||
|
message.random_id = cursor.longValue(5);
|
||||||
|
}
|
||||||
|
if ((int) dialog_id == 0 && message.media != null && message.media.photo != null) {
|
||||||
|
try {
|
||||||
|
SQLiteCursor cursor2 = database.queryFinalized(String.format(Locale.US, "SELECT date FROM enc_tasks_v2 WHERE mid = %d", message.id));
|
||||||
|
if (cursor2.next()) {
|
||||||
|
message.destroyTime = cursor2.intValue(0);
|
||||||
|
}
|
||||||
|
cursor2.dispose();
|
||||||
|
} catch (Exception e) {
|
||||||
|
FileLog.e("tmessages", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buffersStorage.reuseFreeBuffer(data);
|
||||||
|
}
|
||||||
|
cursor.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
Collections.sort(res.messages, new Comparator<TLRPC.Message>() {
|
||||||
|
@Override
|
||||||
|
public int compare(TLRPC.Message lhs, TLRPC.Message rhs) {
|
||||||
|
if (lhs.id > 0 && rhs.id > 0) {
|
||||||
|
if (lhs.id > rhs.id) {
|
||||||
|
return -1;
|
||||||
|
} else if (lhs.id < rhs.id) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} else if (lhs.id < 0 && rhs.id < 0) {
|
||||||
|
if (lhs.id < rhs.id) {
|
||||||
|
return -1;
|
||||||
|
} else if (lhs.id > rhs.id) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (lhs.date > rhs.date) {
|
||||||
|
return -1;
|
||||||
|
} else if (lhs.date < rhs.date) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/*ArrayList<Range<Integer>> holes = getHoles(dialog_id);
|
||||||
|
if (holes != null && !res.messages.isEmpty()) {
|
||||||
|
int start = res.messages.get(res.messages.size() - 1).id;
|
||||||
|
int end = res.messages.get(0).id;
|
||||||
|
for (Range<Integer> range : holes) {
|
||||||
|
if (range.contains(start) && range.contains(end)) {
|
||||||
|
res.messages.clear();
|
||||||
|
} else if (range.contains(start)) {
|
||||||
|
while (!res.messages.isEmpty() && range.contains(res.messages.get(res.messages.size() - 1).id)) {
|
||||||
|
res.messages.remove(res.messages.size() - 1);
|
||||||
|
}
|
||||||
|
if (!res.messages.isEmpty()) {
|
||||||
|
start = res.messages.get(res.messages.size() - 1).id;
|
||||||
|
}
|
||||||
|
} else if (range.contains(end)) {
|
||||||
|
while (!res.messages.isEmpty() && range.contains(res.messages.get(0).id)) {
|
||||||
|
res.messages.remove(0);
|
||||||
|
}
|
||||||
|
if (!res.messages.isEmpty()) {
|
||||||
|
end = res.messages.get(0).id;
|
||||||
|
}
|
||||||
|
} else if (start >= )
|
||||||
|
if (res.messages.isEmpty()) {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
buffersStorage.reuseFreeBuffer(data);
|
}*/
|
||||||
|
|
||||||
Collections.sort(res.messages, new Comparator<TLRPC.Message>() {
|
|
||||||
@Override
|
|
||||||
public int compare(TLRPC.Message lhs, TLRPC.Message rhs) {
|
|
||||||
if (lhs.id > 0 && rhs.id > 0) {
|
|
||||||
if (!forward) {
|
|
||||||
if (lhs.id > rhs.id) {
|
|
||||||
return -1;
|
|
||||||
} else if (lhs.id < rhs.id) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (lhs.id < rhs.id) {
|
|
||||||
return -1;
|
|
||||||
} else if (lhs.id > rhs.id) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (lhs.id < 0 && rhs.id < 0) {
|
|
||||||
if (!forward) {
|
|
||||||
if (lhs.id < rhs.id) {
|
|
||||||
return -1;
|
|
||||||
} else if (lhs.id > rhs.id) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (lhs.id > rhs.id) {
|
|
||||||
return -1;
|
|
||||||
} else if (lhs.id < rhs.id) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!forward) {
|
|
||||||
if (lhs.date > rhs.date) {
|
|
||||||
return -1;
|
|
||||||
} else if (lhs.date < rhs.date) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (lhs.date < rhs.date) {
|
|
||||||
return -1;
|
|
||||||
} else if (lhs.date > rhs.date) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
cursor.dispose();
|
|
||||||
|
|
||||||
StringBuilder usersToLoad = new StringBuilder();
|
StringBuilder usersToLoad = new StringBuilder();
|
||||||
for (int uid : fromUser) {
|
for (int uid : fromUser) {
|
||||||
@ -1926,7 +1898,7 @@ public class MessagesStorage {
|
|||||||
res.users.clear();
|
res.users.clear();
|
||||||
FileLog.e("tmessages", e);
|
FileLog.e("tmessages", e);
|
||||||
} finally {
|
} finally {
|
||||||
MessagesController.getInstance().processLoadedMessages(res, dialog_id, count_query, max_id, true, classGuid, min_unread_id, max_unread_id, count_unread, max_unread_date, forward, semaphore);
|
MessagesController.getInstance().processLoadedMessages(res, dialog_id, count_query, max_id, true, classGuid, min_unread_id, last_message_id, first_message_id, count_unread, max_unread_date, load_type, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -2043,10 +2015,11 @@ public class MessagesStorage {
|
|||||||
public void run() {
|
public void run() {
|
||||||
SQLitePreparedStatement state = null;
|
SQLitePreparedStatement state = null;
|
||||||
try {
|
try {
|
||||||
state = database.executeFast("UPDATE enc_chats SET seq_in = ?, seq_out = ? WHERE uid = ?");
|
state = database.executeFast("UPDATE enc_chats SET seq_in = ?, seq_out = ?, use_count = ? WHERE uid = ?");
|
||||||
state.bindInteger(1, chat.seq_in);
|
state.bindInteger(1, chat.seq_in);
|
||||||
state.bindInteger(2, chat.seq_out);
|
state.bindInteger(2, chat.seq_out);
|
||||||
state.bindInteger(3, chat.id);
|
state.bindInteger(3, (int)chat.key_use_count_in << 16 | chat.key_use_count_out);
|
||||||
|
state.bindInteger(4, chat.id);
|
||||||
state.step();
|
state.step();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
FileLog.e("tmessages", e);
|
FileLog.e("tmessages", e);
|
||||||
@ -2116,10 +2089,18 @@ public class MessagesStorage {
|
|||||||
public void run() {
|
public void run() {
|
||||||
SQLitePreparedStatement state = null;
|
SQLitePreparedStatement state = null;
|
||||||
try {
|
try {
|
||||||
state = database.executeFast("UPDATE enc_chats SET data = ?, g = ?, authkey = ?, ttl = ?, layer = ?, seq_in = ?, seq_out = ? WHERE uid = ?");
|
if ((chat.key_hash == null || chat.key_hash.length != 16) && chat.auth_key != null) {
|
||||||
|
byte[] sha1 = Utilities.computeSHA1(chat.auth_key);
|
||||||
|
chat.key_hash = new byte[16];
|
||||||
|
System.arraycopy(sha1, 0, chat.key_hash, 0, chat.key_hash.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
state = database.executeFast("UPDATE enc_chats SET data = ?, g = ?, authkey = ?, ttl = ?, layer = ?, seq_in = ?, seq_out = ?, use_count = ?, exchange_id = ?, key_date = ?, fprint = ?, fauthkey = ?, khash = ? WHERE uid = ?");
|
||||||
ByteBufferDesc data = buffersStorage.getFreeBuffer(chat.getObjectSize());
|
ByteBufferDesc data = buffersStorage.getFreeBuffer(chat.getObjectSize());
|
||||||
ByteBufferDesc data2 = buffersStorage.getFreeBuffer(chat.a_or_b != null ? chat.a_or_b.length : 1);
|
ByteBufferDesc data2 = buffersStorage.getFreeBuffer(chat.a_or_b != null ? chat.a_or_b.length : 1);
|
||||||
ByteBufferDesc data3 = buffersStorage.getFreeBuffer(chat.auth_key != null ? chat.auth_key.length : 1);
|
ByteBufferDesc data3 = buffersStorage.getFreeBuffer(chat.auth_key != null ? chat.auth_key.length : 1);
|
||||||
|
ByteBufferDesc data4 = buffersStorage.getFreeBuffer(chat.future_auth_key != null ? chat.future_auth_key.length : 1);
|
||||||
|
ByteBufferDesc data5 = buffersStorage.getFreeBuffer(chat.key_hash != null ? chat.key_hash.length : 1);
|
||||||
chat.serializeToStream(data);
|
chat.serializeToStream(data);
|
||||||
state.bindByteBuffer(1, data.buffer);
|
state.bindByteBuffer(1, data.buffer);
|
||||||
if (chat.a_or_b != null) {
|
if (chat.a_or_b != null) {
|
||||||
@ -2128,17 +2109,32 @@ public class MessagesStorage {
|
|||||||
if (chat.auth_key != null) {
|
if (chat.auth_key != null) {
|
||||||
data3.writeRaw(chat.auth_key);
|
data3.writeRaw(chat.auth_key);
|
||||||
}
|
}
|
||||||
|
if (chat.future_auth_key != null) {
|
||||||
|
data4.writeRaw(chat.future_auth_key);
|
||||||
|
}
|
||||||
|
if (chat.key_hash != null) {
|
||||||
|
data5.writeRaw(chat.key_hash);
|
||||||
|
}
|
||||||
state.bindByteBuffer(2, data2.buffer);
|
state.bindByteBuffer(2, data2.buffer);
|
||||||
state.bindByteBuffer(3, data3.buffer);
|
state.bindByteBuffer(3, data3.buffer);
|
||||||
state.bindInteger(4, chat.ttl);
|
state.bindInteger(4, chat.ttl);
|
||||||
state.bindInteger(5, chat.layer);
|
state.bindInteger(5, chat.layer);
|
||||||
state.bindInteger(6, chat.seq_in);
|
state.bindInteger(6, chat.seq_in);
|
||||||
state.bindInteger(7, chat.seq_out);
|
state.bindInteger(7, chat.seq_out);
|
||||||
state.bindInteger(8, chat.id);
|
state.bindInteger(8, (int)chat.key_use_count_in << 16 | chat.key_use_count_out);
|
||||||
|
state.bindLong(9, chat.exchange_id);
|
||||||
|
state.bindInteger(10, chat.key_create_date);
|
||||||
|
state.bindLong(11, chat.future_key_fingerprint);
|
||||||
|
state.bindByteBuffer(12, data4.buffer);
|
||||||
|
state.bindByteBuffer(13, data5.buffer);
|
||||||
|
state.bindInteger(14, chat.id);
|
||||||
|
|
||||||
state.step();
|
state.step();
|
||||||
buffersStorage.reuseFreeBuffer(data);
|
buffersStorage.reuseFreeBuffer(data);
|
||||||
buffersStorage.reuseFreeBuffer(data2);
|
buffersStorage.reuseFreeBuffer(data2);
|
||||||
buffersStorage.reuseFreeBuffer(data3);
|
buffersStorage.reuseFreeBuffer(data3);
|
||||||
|
buffersStorage.reuseFreeBuffer(data4);
|
||||||
|
buffersStorage.reuseFreeBuffer(data5);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
FileLog.e("tmessages", e);
|
FileLog.e("tmessages", e);
|
||||||
} finally {
|
} finally {
|
||||||
@ -2186,10 +2182,17 @@ public class MessagesStorage {
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
SQLitePreparedStatement state = database.executeFast("REPLACE INTO enc_chats VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
|
if ((chat.key_hash == null || chat.key_hash.length != 16) && chat.auth_key != null) {
|
||||||
|
byte[] sha1 = Utilities.computeSHA1(chat.auth_key);
|
||||||
|
chat.key_hash = new byte[16];
|
||||||
|
System.arraycopy(sha1, 0, chat.key_hash, 0, chat.key_hash.length);
|
||||||
|
}
|
||||||
|
SQLitePreparedStatement state = database.executeFast("REPLACE INTO enc_chats VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
|
||||||
ByteBufferDesc data = buffersStorage.getFreeBuffer(chat.getObjectSize());
|
ByteBufferDesc data = buffersStorage.getFreeBuffer(chat.getObjectSize());
|
||||||
ByteBufferDesc data2 = buffersStorage.getFreeBuffer(chat.a_or_b != null ? chat.a_or_b.length : 1);
|
ByteBufferDesc data2 = buffersStorage.getFreeBuffer(chat.a_or_b != null ? chat.a_or_b.length : 1);
|
||||||
ByteBufferDesc data3 = buffersStorage.getFreeBuffer(chat.auth_key != null ? chat.auth_key.length : 1);
|
ByteBufferDesc data3 = buffersStorage.getFreeBuffer(chat.auth_key != null ? chat.auth_key.length : 1);
|
||||||
|
ByteBufferDesc data4 = buffersStorage.getFreeBuffer(chat.future_auth_key != null ? chat.future_auth_key.length : 1);
|
||||||
|
ByteBufferDesc data5 = buffersStorage.getFreeBuffer(chat.key_hash != null ? chat.key_hash.length : 1);
|
||||||
|
|
||||||
chat.serializeToStream(data);
|
chat.serializeToStream(data);
|
||||||
state.bindInteger(1, chat.id);
|
state.bindInteger(1, chat.id);
|
||||||
@ -2202,17 +2205,32 @@ public class MessagesStorage {
|
|||||||
if (chat.auth_key != null) {
|
if (chat.auth_key != null) {
|
||||||
data3.writeRaw(chat.auth_key);
|
data3.writeRaw(chat.auth_key);
|
||||||
}
|
}
|
||||||
|
if (chat.future_auth_key != null) {
|
||||||
|
data4.writeRaw(chat.future_auth_key);
|
||||||
|
}
|
||||||
|
if (chat.key_hash != null) {
|
||||||
|
data5.writeRaw(chat.key_hash);
|
||||||
|
}
|
||||||
state.bindByteBuffer(5, data2.buffer);
|
state.bindByteBuffer(5, data2.buffer);
|
||||||
state.bindByteBuffer(6, data3.buffer);
|
state.bindByteBuffer(6, data3.buffer);
|
||||||
state.bindInteger(7, chat.ttl);
|
state.bindInteger(7, chat.ttl);
|
||||||
state.bindInteger(8, chat.layer);
|
state.bindInteger(8, chat.layer);
|
||||||
state.bindInteger(9, chat.seq_in);
|
state.bindInteger(9, chat.seq_in);
|
||||||
state.bindInteger(10, chat.seq_out);
|
state.bindInteger(10, chat.seq_out);
|
||||||
|
state.bindInteger(11, (int)chat.key_use_count_in << 16 | chat.key_use_count_out);
|
||||||
|
state.bindLong(12, chat.exchange_id);
|
||||||
|
state.bindInteger(13, chat.key_create_date);
|
||||||
|
state.bindLong(14, chat.future_key_fingerprint);
|
||||||
|
state.bindByteBuffer(15, data4.buffer);
|
||||||
|
state.bindByteBuffer(16, data5.buffer);
|
||||||
|
|
||||||
state.step();
|
state.step();
|
||||||
state.dispose();
|
state.dispose();
|
||||||
buffersStorage.reuseFreeBuffer(data);
|
buffersStorage.reuseFreeBuffer(data);
|
||||||
buffersStorage.reuseFreeBuffer(data2);
|
buffersStorage.reuseFreeBuffer(data2);
|
||||||
buffersStorage.reuseFreeBuffer(data3);
|
buffersStorage.reuseFreeBuffer(data3);
|
||||||
|
buffersStorage.reuseFreeBuffer(data4);
|
||||||
|
buffersStorage.reuseFreeBuffer(data5);
|
||||||
|
|
||||||
if (dialog != null) {
|
if (dialog != null) {
|
||||||
state = database.executeFast("REPLACE INTO dialogs(did, date, unread_count, last_mid) VALUES(?, ?, ?, ?)");
|
state = database.executeFast("REPLACE INTO dialogs(did, date, unread_count, last_mid) VALUES(?, ?, ?, ?)");
|
||||||
@ -2260,6 +2278,13 @@ public class MessagesStorage {
|
|||||||
state.bindInteger(1, user.id);
|
state.bindInteger(1, user.id);
|
||||||
state.bindString(2, formatUserSearchName(user));
|
state.bindString(2, formatUserSearchName(user));
|
||||||
if (user.status != null) {
|
if (user.status != null) {
|
||||||
|
if (user.status instanceof TLRPC.TL_userStatusRecently) {
|
||||||
|
user.status.expires = -100;
|
||||||
|
} else if (user.status instanceof TLRPC.TL_userStatusLastWeek) {
|
||||||
|
user.status.expires = -101;
|
||||||
|
} else if (user.status instanceof TLRPC.TL_userStatusLastMonth) {
|
||||||
|
user.status.expires = -102;
|
||||||
|
}
|
||||||
state.bindInteger(3, user.status.expires);
|
state.bindInteger(3, user.status.expires);
|
||||||
} else {
|
} else {
|
||||||
state.bindInteger(3, 0);
|
state.bindInteger(3, 0);
|
||||||
@ -2345,8 +2370,8 @@ public class MessagesStorage {
|
|||||||
if (chatsToLoad == null || chatsToLoad.length() == 0 || result == null) {
|
if (chatsToLoad == null || chatsToLoad.length() == 0 || result == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
//use_count INTEGER, exchange_id INTEGER, key_date INTEGER, fprint INTEGER, fauthkey BLOB
|
||||||
SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, user, g, authkey, ttl, layer, seq_in, seq_out FROM enc_chats WHERE uid IN(%s)", chatsToLoad));
|
SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, user, g, authkey, ttl, layer, seq_in, seq_out, use_count, exchange_id, key_date, fprint, fauthkey, khash FROM enc_chats WHERE uid IN(%s)", chatsToLoad));
|
||||||
while (cursor.next()) {
|
while (cursor.next()) {
|
||||||
try {
|
try {
|
||||||
ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0));
|
ByteBufferDesc data = buffersStorage.getFreeBuffer(cursor.byteArrayLength(0));
|
||||||
@ -2363,6 +2388,14 @@ public class MessagesStorage {
|
|||||||
chat.layer = cursor.intValue(5);
|
chat.layer = cursor.intValue(5);
|
||||||
chat.seq_in = cursor.intValue(6);
|
chat.seq_in = cursor.intValue(6);
|
||||||
chat.seq_out = cursor.intValue(7);
|
chat.seq_out = cursor.intValue(7);
|
||||||
|
int use_count = cursor.intValue(8);
|
||||||
|
chat.key_use_count_in = (short)(use_count >> 16);
|
||||||
|
chat.key_use_count_out = (short)(use_count);
|
||||||
|
chat.exchange_id = cursor.longValue(9);
|
||||||
|
chat.key_create_date = cursor.intValue(10);
|
||||||
|
chat.future_key_fingerprint = cursor.longValue(11);
|
||||||
|
chat.future_auth_key = cursor.byteArrayValue(12);
|
||||||
|
chat.key_hash = cursor.byteArrayValue(13);
|
||||||
result.add(chat);
|
result.add(chat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2467,7 +2500,7 @@ public class MessagesStorage {
|
|||||||
}
|
}
|
||||||
cursor.dispose();
|
cursor.dispose();
|
||||||
|
|
||||||
AndroidUtilities.RunOnUIThread(new Runnable() {
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
MediaController.getInstance().processDownloadObjects(type, objects);
|
MediaController.getInstance().processDownloadObjects(type, objects);
|
||||||
@ -2757,7 +2790,7 @@ public class MessagesStorage {
|
|||||||
|
|
||||||
if (downloadMediaMask != 0) {
|
if (downloadMediaMask != 0) {
|
||||||
final int downloadMediaMaskFinal = downloadMediaMask;
|
final int downloadMediaMaskFinal = downloadMediaMask;
|
||||||
AndroidUtilities.RunOnUIThread(new Runnable() {
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
MediaController.getInstance().newDownloadObjectsAvailable(downloadMediaMaskFinal);
|
MediaController.getInstance().newDownloadObjectsAvailable(downloadMediaMaskFinal);
|
||||||
@ -2798,6 +2831,60 @@ public class MessagesStorage {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*public void getHoleMessages() {
|
||||||
|
storageQueue.postRunnable(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
FileLog.e("tmessages", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearHoleMessages(final int enc_id) {
|
||||||
|
storageQueue.postRunnable(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
database.executeFast("DELETE FROM secret_holes WHERE uid = " + enc_id).stepThis().dispose();
|
||||||
|
} catch (Exception e) {
|
||||||
|
FileLog.e("tmessages", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void putHoleMessage(final int enc_id, final TLRPC.Message message) {
|
||||||
|
if (message == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
storageQueue.postRunnable(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
SQLitePreparedStatement state = database.executeFast("REPLACE INTO secret_holes VALUES(?, ?, ?, ?)");
|
||||||
|
|
||||||
|
state.requery();
|
||||||
|
ByteBufferDesc data = buffersStorage.getFreeBuffer(message.getObjectSize());
|
||||||
|
message.serializeToStream(data);
|
||||||
|
state.bindInteger(1, enc_id);
|
||||||
|
state.bindInteger(2, message.seq_in);
|
||||||
|
state.bindInteger(3, message.seq_out);
|
||||||
|
state.bindByteBuffer(4, data.buffer);
|
||||||
|
state.step();
|
||||||
|
buffersStorage.reuseFreeBuffer(data);
|
||||||
|
|
||||||
|
state.dispose();
|
||||||
|
} catch (Exception e) {
|
||||||
|
FileLog.e("tmessages", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}*/
|
||||||
|
|
||||||
public void setMessageSeq(final int mid, final int seq_in, final int seq_out) {
|
public void setMessageSeq(final int mid, final int seq_in, final int seq_out) {
|
||||||
storageQueue.postRunnable(new Runnable() {
|
storageQueue.postRunnable(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
@ -2968,6 +3055,8 @@ public class MessagesStorage {
|
|||||||
user.username = updateUser.username;
|
user.username = updateUser.username;
|
||||||
} else if (updateUser.photo != null) {
|
} else if (updateUser.photo != null) {
|
||||||
user.photo = updateUser.photo;
|
user.photo = updateUser.photo;
|
||||||
|
} else if (updateUser.phone != null) {
|
||||||
|
user.phone = updateUser.phone;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3058,7 +3147,7 @@ public class MessagesStorage {
|
|||||||
}
|
}
|
||||||
cursor.dispose();
|
cursor.dispose();
|
||||||
if (!mids.isEmpty()) {
|
if (!mids.isEmpty()) {
|
||||||
AndroidUtilities.RunOnUIThread(new Runnable() {
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
for (Integer id : mids) {
|
for (Integer id : mids) {
|
||||||
|
@ -23,12 +23,10 @@ import java.util.zip.ZipFile;
|
|||||||
|
|
||||||
public class NativeLoader {
|
public class NativeLoader {
|
||||||
|
|
||||||
private static final long sizes[] = new long[] {
|
private final static int LIB_VERSION = 4;
|
||||||
955148, //armeabi
|
private final static String LIB_NAME = "tmessages." + LIB_VERSION;
|
||||||
1041184, //armeabi-v7a
|
private final static String LIB_SO_NAME = "lib" + LIB_NAME + ".so";
|
||||||
1616116, //x86
|
private final static String LOCALE_LIB_SO_NAME = "lib" + LIB_NAME + "loc.so";
|
||||||
0, //mips
|
|
||||||
};
|
|
||||||
|
|
||||||
private static volatile boolean nativeLoaded = false;
|
private static volatile boolean nativeLoaded = false;
|
||||||
|
|
||||||
@ -50,14 +48,22 @@ public class NativeLoader {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean loadFromZip(Context context, File destLocalFile, String folder) {
|
private static boolean loadFromZip(Context context, File destDir, File destLocalFile, String folder) {
|
||||||
|
try {
|
||||||
|
for (File file : destDir.listFiles()) {
|
||||||
|
file.delete();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
FileLog.e("tmessages", e);
|
||||||
|
}
|
||||||
|
|
||||||
ZipFile zipFile = null;
|
ZipFile zipFile = null;
|
||||||
InputStream stream = null;
|
InputStream stream = null;
|
||||||
try {
|
try {
|
||||||
zipFile = new ZipFile(context.getApplicationInfo().sourceDir);
|
zipFile = new ZipFile(context.getApplicationInfo().sourceDir);
|
||||||
ZipEntry entry = zipFile.getEntry("lib/" + folder + "/libtmessages.so");
|
ZipEntry entry = zipFile.getEntry("lib/" + folder + "/" + LIB_SO_NAME);
|
||||||
if (entry == null) {
|
if (entry == null) {
|
||||||
throw new Exception("Unable to find file in apk:" + "lib/" + folder + "/libtmessages.so");
|
throw new Exception("Unable to find file in apk:" + "lib/" + folder + "/" + LIB_NAME);
|
||||||
}
|
}
|
||||||
stream = zipFile.getInputStream(entry);
|
stream = zipFile.getInputStream(entry);
|
||||||
|
|
||||||
@ -70,6 +76,12 @@ public class NativeLoader {
|
|||||||
}
|
}
|
||||||
out.close();
|
out.close();
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= 9) {
|
||||||
|
destLocalFile.setReadable(true, false);
|
||||||
|
destLocalFile.setExecutable(true, false);
|
||||||
|
destLocalFile.setWritable(true);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
System.load(destLocalFile.getAbsolutePath());
|
System.load(destLocalFile.getAbsolutePath());
|
||||||
nativeLoaded = true;
|
nativeLoaded = true;
|
||||||
@ -105,50 +117,38 @@ public class NativeLoader {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
String folder = null;
|
String folder = null;
|
||||||
long libSize = 0;
|
|
||||||
long libSize2 = 0;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (Build.CPU_ABI.equalsIgnoreCase("armeabi-v7a")) {
|
if (Build.CPU_ABI.equalsIgnoreCase("armeabi-v7a")) {
|
||||||
folder = "armeabi-v7a";
|
folder = "armeabi-v7a";
|
||||||
libSize = sizes[1];
|
|
||||||
libSize2 = sizes[0];
|
|
||||||
} else if (Build.CPU_ABI.equalsIgnoreCase("armeabi")) {
|
} else if (Build.CPU_ABI.equalsIgnoreCase("armeabi")) {
|
||||||
folder = "armeabi";
|
folder = "armeabi";
|
||||||
libSize = sizes[0];
|
|
||||||
libSize2 = sizes[1];
|
|
||||||
} else if (Build.CPU_ABI.equalsIgnoreCase("x86")) {
|
} else if (Build.CPU_ABI.equalsIgnoreCase("x86")) {
|
||||||
folder = "x86";
|
folder = "x86";
|
||||||
libSize = sizes[2];
|
|
||||||
} else if (Build.CPU_ABI.equalsIgnoreCase("mips")) {
|
} else if (Build.CPU_ABI.equalsIgnoreCase("mips")) {
|
||||||
folder = "mips";
|
folder = "mips";
|
||||||
libSize = sizes[3];
|
|
||||||
} else {
|
} else {
|
||||||
folder = "armeabi";
|
folder = "armeabi";
|
||||||
libSize = sizes[0];
|
|
||||||
libSize2 = sizes[1];
|
|
||||||
FileLog.e("tmessages", "Unsupported arch: " + Build.CPU_ABI);
|
FileLog.e("tmessages", "Unsupported arch: " + Build.CPU_ABI);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
FileLog.e("tmessages", e);
|
FileLog.e("tmessages", e);
|
||||||
folder = "armeabi";
|
folder = "armeabi";
|
||||||
libSize = sizes[0];
|
|
||||||
libSize2 = sizes[1];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
String javaArch = System.getProperty("os.arch");
|
String javaArch = System.getProperty("os.arch");
|
||||||
if (javaArch != null && javaArch.contains("686")) {
|
if (javaArch != null && javaArch.contains("686")) {
|
||||||
folder = "x86";
|
folder = "x86";
|
||||||
libSize = sizes[2];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
File destFile = getNativeLibraryDir(context);
|
File destFile = getNativeLibraryDir(context);
|
||||||
if (destFile != null) {
|
if (destFile != null) {
|
||||||
destFile = new File(destFile, "libtmessages.so");
|
destFile = new File(destFile, LIB_SO_NAME);
|
||||||
if (destFile.exists() && (destFile.length() == libSize || libSize2 != 0 && destFile.length() == libSize2)) {
|
if (destFile.exists()) {
|
||||||
FileLog.d("tmessages", "Load normal lib");
|
FileLog.d("tmessages", "Load normal lib");
|
||||||
try {
|
try {
|
||||||
System.loadLibrary("tmessages");
|
System.loadLibrary(LIB_NAME);
|
||||||
nativeLoaded = true;
|
nativeLoaded = true;
|
||||||
return;
|
return;
|
||||||
} catch (Error e) {
|
} catch (Error e) {
|
||||||
@ -157,39 +157,43 @@ public class NativeLoader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
File destLocalFile = new File(context.getFilesDir().getAbsolutePath() + "/libtmessages.so");
|
File destDir = new File(context.getFilesDir(), "lib");
|
||||||
|
destDir.mkdirs();
|
||||||
|
|
||||||
|
File destLocalFile = new File(destDir, LOCALE_LIB_SO_NAME);
|
||||||
if (destLocalFile != null && destLocalFile.exists()) {
|
if (destLocalFile != null && destLocalFile.exists()) {
|
||||||
if (destLocalFile.length() == libSize) {
|
try {
|
||||||
try {
|
FileLog.d("tmessages", "Load local lib");
|
||||||
FileLog.d("tmessages", "Load local lib");
|
System.load(destLocalFile.getAbsolutePath());
|
||||||
System.load(destLocalFile.getAbsolutePath());
|
nativeLoaded = true;
|
||||||
nativeLoaded = true;
|
return;
|
||||||
return;
|
} catch (Error e) {
|
||||||
} catch (Error e) {
|
FileLog.e("tmessages", e);
|
||||||
FileLog.e("tmessages", e);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
destLocalFile.delete();
|
|
||||||
}
|
}
|
||||||
|
destLocalFile.delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
FileLog.e("tmessages", "Library not found, arch = " + folder);
|
FileLog.e("tmessages", "Library not found, arch = " + folder);
|
||||||
|
|
||||||
if (!loadFromZip(context, destLocalFile, folder)) {
|
if (loadFromZip(context, destDir, destLocalFile, folder)) {
|
||||||
folder = "x86";
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
folder = "x86";
|
||||||
destLocalFile = new File(context.getFilesDir().getAbsolutePath() + "/libtmessages86.so");
|
destLocalFile = new File(context.getFilesDir().getAbsolutePath() + "/libtmessages86.so");
|
||||||
if (!loadFromZip(context, destLocalFile, folder)) {
|
if (!loadFromZip(context, destLocalFile, folder)) {
|
||||||
destLocalFile = new File(context.getFilesDir().getAbsolutePath() + "/libtmessagesarm.so");
|
destLocalFile = new File(context.getFilesDir().getAbsolutePath() + "/libtmessagesarm.so");
|
||||||
folder = "armeabi";
|
folder = "armeabi";
|
||||||
loadFromZip(context, destLocalFile, folder);
|
loadFromZip(context, destLocalFile, folder);
|
||||||
}
|
}
|
||||||
}
|
*/
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
System.loadLibrary("tmessages");
|
System.loadLibrary(LIB_NAME);
|
||||||
nativeLoaded = true;
|
nativeLoaded = true;
|
||||||
} catch (Error e) {
|
} catch (Error e) {
|
||||||
FileLog.e("tmessages", e);
|
FileLog.e("tmessages", e);
|
||||||
|
@ -23,7 +23,6 @@ public class NotificationCenter {
|
|||||||
public static final int messageReceivedByAck = 9;
|
public static final int messageReceivedByAck = 9;
|
||||||
public static final int messageReceivedByServer = 10;
|
public static final int messageReceivedByServer = 10;
|
||||||
public static final int messageSendError = 11;
|
public static final int messageSendError = 11;
|
||||||
public static final int reloadSearchResults = 12;
|
|
||||||
public static final int contactsDidLoaded = 13;
|
public static final int contactsDidLoaded = 13;
|
||||||
public static final int chatDidCreated = 15;
|
public static final int chatDidCreated = 15;
|
||||||
public static final int chatDidFailCreate = 16;
|
public static final int chatDidFailCreate = 16;
|
||||||
@ -42,10 +41,13 @@ public class NotificationCenter {
|
|||||||
public static final int hideEmojiKeyboard = 30;
|
public static final int hideEmojiKeyboard = 30;
|
||||||
public static final int stopEncodingService = 31;
|
public static final int stopEncodingService = 31;
|
||||||
public static final int didCreatedNewDeleteTask = 32;
|
public static final int didCreatedNewDeleteTask = 32;
|
||||||
|
public static final int mainUserInfoChanged = 33;
|
||||||
|
public static final int privacyRulesUpdated = 34;
|
||||||
|
|
||||||
public static final int wallpapersDidLoaded = 171;
|
public static final int wallpapersDidLoaded = 171;
|
||||||
public static final int closeOtherAppActivities = 702;
|
public static final int closeOtherAppActivities = 702;
|
||||||
public static final int didUpdatedConnectionState = 703;
|
public static final int didUpdatedConnectionState = 703;
|
||||||
|
public static final int didReceiveSmsCode = 998;
|
||||||
public static final int emojiDidLoaded = 999;
|
public static final int emojiDidLoaded = 999;
|
||||||
public static final int appDidLogout = 1234;
|
public static final int appDidLogout = 1234;
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ public class NotificationRepeat extends IntentService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onHandleIntent(Intent intent) {
|
protected void onHandleIntent(Intent intent) {
|
||||||
AndroidUtilities.RunOnUIThread(new Runnable() {
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
NotificationsController.getInstance().repeatNotificationMaybe();
|
NotificationsController.getInstance().repeatNotificationMaybe();
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
package org.telegram.android;
|
package org.telegram.android;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
import android.app.AlarmManager;
|
import android.app.AlarmManager;
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
@ -32,7 +33,7 @@ import org.telegram.messenger.FileLog;
|
|||||||
import org.telegram.messenger.R;
|
import org.telegram.messenger.R;
|
||||||
import org.telegram.messenger.TLRPC;
|
import org.telegram.messenger.TLRPC;
|
||||||
import org.telegram.messenger.UserConfig;
|
import org.telegram.messenger.UserConfig;
|
||||||
import org.telegram.ui.ApplicationLoader;
|
import org.telegram.messenger.ApplicationLoader;
|
||||||
import org.telegram.ui.LaunchActivity;
|
import org.telegram.ui.LaunchActivity;
|
||||||
import org.telegram.ui.PopupNotificationActivity;
|
import org.telegram.ui.PopupNotificationActivity;
|
||||||
|
|
||||||
@ -235,8 +236,10 @@ public class NotificationsController {
|
|||||||
try {
|
try {
|
||||||
AlarmManager alarm = (AlarmManager) ApplicationLoader.applicationContext.getSystemService(Context.ALARM_SERVICE);
|
AlarmManager alarm = (AlarmManager) ApplicationLoader.applicationContext.getSystemService(Context.ALARM_SERVICE);
|
||||||
PendingIntent pintent = PendingIntent.getService(ApplicationLoader.applicationContext, 0, new Intent(ApplicationLoader.applicationContext, NotificationRepeat.class), 0);
|
PendingIntent pintent = PendingIntent.getService(ApplicationLoader.applicationContext, 0, new Intent(ApplicationLoader.applicationContext, NotificationRepeat.class), 0);
|
||||||
if (personal_count > 0) {
|
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE);
|
||||||
alarm.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + 60 * 60 * 1000, pintent);
|
int minutes = preferences.getInt("repeat_messages", 60);
|
||||||
|
if (minutes > 0 && personal_count > 0) {
|
||||||
|
alarm.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + minutes * 60 * 1000, pintent);
|
||||||
} else {
|
} else {
|
||||||
alarm.cancel(pintent);
|
alarm.cancel(pintent);
|
||||||
}
|
}
|
||||||
@ -289,6 +292,9 @@ public class NotificationsController {
|
|||||||
boolean inAppSounds = false;
|
boolean inAppSounds = false;
|
||||||
boolean inAppVibrate = false;
|
boolean inAppVibrate = false;
|
||||||
boolean inAppPreview = false;
|
boolean inAppPreview = false;
|
||||||
|
boolean inAppPriority = false;
|
||||||
|
int priority = 0;
|
||||||
|
int priority_override = 0;
|
||||||
int vibrate_override = 0;
|
int vibrate_override = 0;
|
||||||
|
|
||||||
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Context.MODE_PRIVATE);
|
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Context.MODE_PRIVATE);
|
||||||
@ -302,7 +308,9 @@ public class NotificationsController {
|
|||||||
inAppSounds = preferences.getBoolean("EnableInAppSounds", true);
|
inAppSounds = preferences.getBoolean("EnableInAppSounds", true);
|
||||||
inAppVibrate = preferences.getBoolean("EnableInAppVibrate", true);
|
inAppVibrate = preferences.getBoolean("EnableInAppVibrate", true);
|
||||||
inAppPreview = preferences.getBoolean("EnableInAppPreview", true);
|
inAppPreview = preferences.getBoolean("EnableInAppPreview", true);
|
||||||
|
inAppPriority = preferences.getBoolean("EnableInAppPriority", false);
|
||||||
vibrate_override = preferences.getInt("vibrate_" + dialog_id, 0);
|
vibrate_override = preferences.getInt("vibrate_" + dialog_id, 0);
|
||||||
|
priority_override = preferences.getInt("priority_" + dialog_id, 3);
|
||||||
|
|
||||||
choosenSoundPath = preferences.getString("sound_path_" + dialog_id, null);
|
choosenSoundPath = preferences.getString("sound_path_" + dialog_id, null);
|
||||||
if (chat_id != 0) {
|
if (chat_id != 0) {
|
||||||
@ -312,6 +320,7 @@ public class NotificationsController {
|
|||||||
choosenSoundPath = preferences.getString("GroupSoundPath", defaultPath);
|
choosenSoundPath = preferences.getString("GroupSoundPath", defaultPath);
|
||||||
}
|
}
|
||||||
needVibrate = preferences.getInt("vibrate_group", 0);
|
needVibrate = preferences.getInt("vibrate_group", 0);
|
||||||
|
priority = preferences.getInt("priority_group", 1);
|
||||||
ledColor = preferences.getInt("GroupLed", 0xff00ff00);
|
ledColor = preferences.getInt("GroupLed", 0xff00ff00);
|
||||||
} else if (user_id != 0) {
|
} else if (user_id != 0) {
|
||||||
if (choosenSoundPath != null && choosenSoundPath.equals(defaultPath)) {
|
if (choosenSoundPath != null && choosenSoundPath.equals(defaultPath)) {
|
||||||
@ -320,12 +329,17 @@ public class NotificationsController {
|
|||||||
choosenSoundPath = preferences.getString("GlobalSoundPath", defaultPath);
|
choosenSoundPath = preferences.getString("GlobalSoundPath", defaultPath);
|
||||||
}
|
}
|
||||||
needVibrate = preferences.getInt("vibrate_messages", 0);
|
needVibrate = preferences.getInt("vibrate_messages", 0);
|
||||||
|
priority = preferences.getInt("priority_group", 1);
|
||||||
ledColor = preferences.getInt("MessagesLed", 0xff00ff00);
|
ledColor = preferences.getInt("MessagesLed", 0xff00ff00);
|
||||||
}
|
}
|
||||||
if (preferences.contains("color_" + dialog_id)) {
|
if (preferences.contains("color_" + dialog_id)) {
|
||||||
ledColor = preferences.getInt("color_" + dialog_id, 0);
|
ledColor = preferences.getInt("color_" + dialog_id, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (priority_override != 3) {
|
||||||
|
priority = priority_override;
|
||||||
|
}
|
||||||
|
|
||||||
if (needVibrate == 2 && (vibrate_override == 1 || vibrate_override == 3 || vibrate_override == 5) || needVibrate != 2 && vibrate_override == 2 || vibrate_override != 0) {
|
if (needVibrate == 2 && (vibrate_override == 1 || vibrate_override == 3 || vibrate_override == 5) || needVibrate != 2 && vibrate_override == 2 || vibrate_override != 0) {
|
||||||
needVibrate = vibrate_override;
|
needVibrate = vibrate_override;
|
||||||
}
|
}
|
||||||
@ -336,6 +350,11 @@ public class NotificationsController {
|
|||||||
if (!inAppVibrate) {
|
if (!inAppVibrate) {
|
||||||
needVibrate = 2;
|
needVibrate = 2;
|
||||||
}
|
}
|
||||||
|
if (!inAppPriority) {
|
||||||
|
priority = 0;
|
||||||
|
} else if (priority == 2) {
|
||||||
|
priority = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -397,6 +416,22 @@ public class NotificationsController {
|
|||||||
.setGroup("messages")
|
.setGroup("messages")
|
||||||
.setGroupSummary(true);
|
.setGroupSummary(true);
|
||||||
|
|
||||||
|
if (priority == 0) {
|
||||||
|
mBuilder.setPriority(NotificationCompat.PRIORITY_DEFAULT);
|
||||||
|
} else if (priority == 1) {
|
||||||
|
mBuilder.setPriority(NotificationCompat.PRIORITY_HIGH);
|
||||||
|
} else if (priority == 2) {
|
||||||
|
mBuilder.setPriority(NotificationCompat.PRIORITY_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
mBuilder.setCategory(NotificationCompat.CATEGORY_MESSAGE);
|
||||||
|
if (chat == null && user != null && user.phone != null && user.phone.length() > 0) {
|
||||||
|
mBuilder.addPerson("tel:+" + user.phone);
|
||||||
|
}
|
||||||
|
/*Bundle bundle = new Bundle();
|
||||||
|
bundle.putString(NotificationCompat.EXTRA_PEOPLE, );
|
||||||
|
mBuilder.setExtras()*/
|
||||||
|
|
||||||
String lastMessage = null;
|
String lastMessage = null;
|
||||||
String lastMessageFull = null;
|
String lastMessageFull = null;
|
||||||
if (pushMessages.size() == 1) {
|
if (pushMessages.size() == 1) {
|
||||||
@ -600,7 +635,12 @@ public class NotificationsController {
|
|||||||
.setContentText(text)
|
.setContentText(text)
|
||||||
.setGroupSummary(false)
|
.setGroupSummary(false)
|
||||||
.setContentIntent(contentIntent)
|
.setContentIntent(contentIntent)
|
||||||
.extend(new NotificationCompat.WearableExtender().addAction(action));
|
.extend(new NotificationCompat.WearableExtender().addAction(action))
|
||||||
|
.setCategory(NotificationCompat.CATEGORY_MESSAGE);
|
||||||
|
|
||||||
|
if (chat == null && user != null && user.phone != null && user.phone.length() > 0) {
|
||||||
|
builder.addPerson("tel:+" + user.phone);
|
||||||
|
}
|
||||||
|
|
||||||
notificationManager.notify(notificationId, builder.build());
|
notificationManager.notify(notificationId, builder.build());
|
||||||
wearNoticationsIds.put(dialog_id, notificationId);
|
wearNoticationsIds.put(dialog_id, notificationId);
|
||||||
|
@ -14,7 +14,7 @@ import android.content.SharedPreferences;
|
|||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
|
|
||||||
import org.telegram.messenger.FileLog;
|
import org.telegram.messenger.FileLog;
|
||||||
import org.telegram.ui.ApplicationLoader;
|
import org.telegram.messenger.ApplicationLoader;
|
||||||
|
|
||||||
public class NotificationsService extends Service {
|
public class NotificationsService extends Service {
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@ import org.telegram.messenger.Utilities;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
public class PhotoObject {
|
public class PhotoObject {
|
||||||
|
|
||||||
public TLRPC.PhotoSize photoOwner;
|
public TLRPC.PhotoSize photoOwner;
|
||||||
public Bitmap image;
|
public Bitmap image;
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ import android.content.Intent;
|
|||||||
|
|
||||||
import org.telegram.messenger.ConnectionsManager;
|
import org.telegram.messenger.ConnectionsManager;
|
||||||
import org.telegram.messenger.FileLog;
|
import org.telegram.messenger.FileLog;
|
||||||
import org.telegram.ui.ApplicationLoader;
|
import org.telegram.messenger.ApplicationLoader;
|
||||||
|
|
||||||
public class ScreenReceiver extends BroadcastReceiver {
|
public class ScreenReceiver extends BroadcastReceiver {
|
||||||
@Override
|
@Override
|
||||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -48,7 +48,7 @@ public class SmsListener extends BroadcastReceiver {
|
|||||||
if (matcher.find()) {
|
if (matcher.find()) {
|
||||||
String str = matcher.group(0);
|
String str = matcher.group(0);
|
||||||
if (str.length() >= 3) {
|
if (str.length() >= 3) {
|
||||||
NotificationCenter.getInstance().postNotificationName(998, matcher.group(0));
|
NotificationCenter.getInstance().postNotificationName(NotificationCenter.didReceiveSmsCode, matcher.group(0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -16,7 +16,7 @@ import android.support.v4.app.NotificationManagerCompat;
|
|||||||
|
|
||||||
import org.telegram.messenger.FileLog;
|
import org.telegram.messenger.FileLog;
|
||||||
import org.telegram.messenger.R;
|
import org.telegram.messenger.R;
|
||||||
import org.telegram.ui.ApplicationLoader;
|
import org.telegram.messenger.ApplicationLoader;
|
||||||
|
|
||||||
public class VideoEncodingService extends Service implements NotificationCenter.NotificationCenterDelegate {
|
public class VideoEncodingService extends Service implements NotificationCenter.NotificationCenterDelegate {
|
||||||
|
|
||||||
|
@ -0,0 +1,107 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.telegram.android.time;
|
||||||
|
|
||||||
|
import java.text.ParseException;
|
||||||
|
import java.text.ParsePosition;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>DateParser is the "missing" interface for the parsing methods of
|
||||||
|
* {@link java.text.DateFormat}.</p>
|
||||||
|
*
|
||||||
|
* @since 3.2
|
||||||
|
*/
|
||||||
|
public interface DateParser {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Equivalent to DateFormat.parse(String).
|
||||||
|
* <p/>
|
||||||
|
* See {@link java.text.DateFormat#parse(String)} for more information.
|
||||||
|
*
|
||||||
|
* @param source A <code>String</code> whose beginning should be parsed.
|
||||||
|
* @return A <code>Date</code> parsed from the string
|
||||||
|
* @throws ParseException if the beginning of the specified string cannot be parsed.
|
||||||
|
*/
|
||||||
|
Date parse(String source) throws ParseException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Equivalent to DateFormat.parse(String, ParsePosition).
|
||||||
|
* <p/>
|
||||||
|
* See {@link java.text.DateFormat#parse(String, ParsePosition)} for more information.
|
||||||
|
*
|
||||||
|
* @param source A <code>String</code>, part of which should be parsed.
|
||||||
|
* @param pos A <code>ParsePosition</code> object with index and error index information
|
||||||
|
* as described above.
|
||||||
|
* @return A <code>Date</code> parsed from the string. In case of error, returns null.
|
||||||
|
* @throws NullPointerException if text or pos is null.
|
||||||
|
*/
|
||||||
|
Date parse(String source, ParsePosition pos);
|
||||||
|
|
||||||
|
// Accessors
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Get the pattern used by this parser.</p>
|
||||||
|
*
|
||||||
|
* @return the pattern, {@link java.text.SimpleDateFormat} compatible
|
||||||
|
*/
|
||||||
|
String getPattern();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Get the time zone used by this parser.
|
||||||
|
* </p>
|
||||||
|
* <p/>
|
||||||
|
* <p>
|
||||||
|
* The default {@link TimeZone} used to create a {@link Date} when the {@link TimeZone} is not specified by
|
||||||
|
* the format pattern.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @return the time zone
|
||||||
|
*/
|
||||||
|
TimeZone getTimeZone();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Get the locale used by this parser.</p>
|
||||||
|
*
|
||||||
|
* @return the locale
|
||||||
|
*/
|
||||||
|
Locale getLocale();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses text from a string to produce a Date.
|
||||||
|
*
|
||||||
|
* @param source A <code>String</code> whose beginning should be parsed.
|
||||||
|
* @return a <code>java.util.Date</code> object
|
||||||
|
* @throws ParseException if the beginning of the specified string cannot be parsed.
|
||||||
|
* @see java.text.DateFormat#parseObject(String)
|
||||||
|
*/
|
||||||
|
Object parseObject(String source) throws ParseException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a date/time string according to the given parse position.
|
||||||
|
*
|
||||||
|
* @param source A <code>String</code> whose beginning should be parsed.
|
||||||
|
* @param pos the parse position
|
||||||
|
* @return a <code>java.util.Date</code> object
|
||||||
|
* @see java.text.DateFormat#parseObject(String, ParsePosition)
|
||||||
|
*/
|
||||||
|
Object parseObject(String source, ParsePosition pos);
|
||||||
|
}
|
@ -0,0 +1,126 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.telegram.android.time;
|
||||||
|
|
||||||
|
import java.text.FieldPosition;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>DatePrinter is the "missing" interface for the format methods of
|
||||||
|
* {@link java.text.DateFormat}.</p>
|
||||||
|
*
|
||||||
|
* @since 3.2
|
||||||
|
*/
|
||||||
|
public interface DatePrinter {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Formats a millisecond {@code long} value.</p>
|
||||||
|
*
|
||||||
|
* @param millis the millisecond value to format
|
||||||
|
* @return the formatted string
|
||||||
|
* @since 2.1
|
||||||
|
*/
|
||||||
|
String format(long millis);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Formats a {@code Date} object using a {@code GregorianCalendar}.</p>
|
||||||
|
*
|
||||||
|
* @param date the date to format
|
||||||
|
* @return the formatted string
|
||||||
|
*/
|
||||||
|
String format(Date date);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Formats a {@code Calendar} object.</p>
|
||||||
|
*
|
||||||
|
* @param calendar the calendar to format
|
||||||
|
* @return the formatted string
|
||||||
|
*/
|
||||||
|
String format(Calendar calendar);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Formats a milliseond {@code long} value into the
|
||||||
|
* supplied {@code StringBuffer}.</p>
|
||||||
|
*
|
||||||
|
* @param millis the millisecond value to format
|
||||||
|
* @param buf the buffer to format into
|
||||||
|
* @return the specified string buffer
|
||||||
|
*/
|
||||||
|
StringBuffer format(long millis, StringBuffer buf);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Formats a {@code Date} object into the
|
||||||
|
* supplied {@code StringBuffer} using a {@code GregorianCalendar}.</p>
|
||||||
|
*
|
||||||
|
* @param date the date to format
|
||||||
|
* @param buf the buffer to format into
|
||||||
|
* @return the specified string buffer
|
||||||
|
*/
|
||||||
|
StringBuffer format(Date date, StringBuffer buf);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Formats a {@code Calendar} object into the
|
||||||
|
* supplied {@code StringBuffer}.</p>
|
||||||
|
*
|
||||||
|
* @param calendar the calendar to format
|
||||||
|
* @param buf the buffer to format into
|
||||||
|
* @return the specified string buffer
|
||||||
|
*/
|
||||||
|
StringBuffer format(Calendar calendar, StringBuffer buf);
|
||||||
|
|
||||||
|
// Accessors
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Gets the pattern used by this printer.</p>
|
||||||
|
*
|
||||||
|
* @return the pattern, {@link java.text.SimpleDateFormat} compatible
|
||||||
|
*/
|
||||||
|
String getPattern();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Gets the time zone used by this printer.</p>
|
||||||
|
* <p/>
|
||||||
|
* <p>This zone is always used for {@code Date} printing. </p>
|
||||||
|
*
|
||||||
|
* @return the time zone
|
||||||
|
*/
|
||||||
|
TimeZone getTimeZone();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Gets the locale used by this printer.</p>
|
||||||
|
*
|
||||||
|
* @return the locale
|
||||||
|
*/
|
||||||
|
Locale getLocale();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Formats a {@code Date}, {@code Calendar} or
|
||||||
|
* {@code Long} (milliseconds) object.</p>
|
||||||
|
* <p/>
|
||||||
|
* See {@link java.text.DateFormat#format(Object, StringBuffer, FieldPosition)}
|
||||||
|
*
|
||||||
|
* @param obj the object to format
|
||||||
|
* @param toAppendTo the buffer to append to
|
||||||
|
* @param pos the position - ignored
|
||||||
|
* @return the buffer passed in
|
||||||
|
*/
|
||||||
|
StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos);
|
||||||
|
}
|
@ -0,0 +1,613 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.telegram.android.time;
|
||||||
|
|
||||||
|
import java.text.DateFormat;
|
||||||
|
import java.text.FieldPosition;
|
||||||
|
import java.text.Format;
|
||||||
|
import java.text.ParseException;
|
||||||
|
import java.text.ParsePosition;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>FastDateFormat is a fast and thread-safe version of
|
||||||
|
* {@link java.text.SimpleDateFormat}.</p>
|
||||||
|
*
|
||||||
|
* <p>This class can be used as a direct replacement to
|
||||||
|
* {@code SimpleDateFormat} in most formatting and parsing situations.
|
||||||
|
* This class is especially useful in multi-threaded server environments.
|
||||||
|
* {@code SimpleDateFormat} is not thread-safe in any JDK version,
|
||||||
|
* nor will it be as Sun have closed the bug/RFE.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <p>All patterns are compatible with
|
||||||
|
* SimpleDateFormat (except time zones and some year patterns - see below).</p>
|
||||||
|
*
|
||||||
|
* <p>Since 3.2, FastDateFormat supports parsing as well as printing.</p>
|
||||||
|
*
|
||||||
|
* <p>Java 1.4 introduced a new pattern letter, {@code 'Z'}, to represent
|
||||||
|
* time zones in RFC822 format (eg. {@code +0800} or {@code -1100}).
|
||||||
|
* This pattern letter can be used here (on all JDK versions).</p>
|
||||||
|
*
|
||||||
|
* <p>In addition, the pattern {@code 'ZZ'} has been made to represent
|
||||||
|
* ISO8601 full format time zones (eg. {@code +08:00} or {@code -11:00}).
|
||||||
|
* This introduces a minor incompatibility with Java 1.4, but at a gain of
|
||||||
|
* useful functionality.</p>
|
||||||
|
*
|
||||||
|
* <p>Javadoc cites for the year pattern: <i>For formatting, if the number of
|
||||||
|
* pattern letters is 2, the year is truncated to 2 digits; otherwise it is
|
||||||
|
* interpreted as a number.</i> Starting with Java 1.7 a pattern of 'Y' or
|
||||||
|
* 'YYY' will be formatted as '2003', while it was '03' in former Java
|
||||||
|
* versions. FastDateFormat implements the behavior of Java 7.</p>
|
||||||
|
*
|
||||||
|
* @since 2.0
|
||||||
|
* @version $Id: FastDateFormat.java 1572877 2014-02-28 08:42:25Z britter $
|
||||||
|
*/
|
||||||
|
public class FastDateFormat extends Format implements DateParser, DatePrinter {
|
||||||
|
/**
|
||||||
|
* Required for serialization support.
|
||||||
|
*
|
||||||
|
* @see java.io.Serializable
|
||||||
|
*/
|
||||||
|
private static final long serialVersionUID = 2L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FULL locale dependent date or time style.
|
||||||
|
*/
|
||||||
|
public static final int FULL = DateFormat.FULL;
|
||||||
|
/**
|
||||||
|
* LONG locale dependent date or time style.
|
||||||
|
*/
|
||||||
|
public static final int LONG = DateFormat.LONG;
|
||||||
|
/**
|
||||||
|
* MEDIUM locale dependent date or time style.
|
||||||
|
*/
|
||||||
|
public static final int MEDIUM = DateFormat.MEDIUM;
|
||||||
|
/**
|
||||||
|
* SHORT locale dependent date or time style.
|
||||||
|
*/
|
||||||
|
public static final int SHORT = DateFormat.SHORT;
|
||||||
|
|
||||||
|
private static final FormatCache<FastDateFormat> cache = new FormatCache<FastDateFormat>() {
|
||||||
|
@Override
|
||||||
|
protected FastDateFormat createInstance(final String pattern, final TimeZone timeZone, final Locale locale) {
|
||||||
|
return new FastDateFormat(pattern, timeZone, locale);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private final FastDatePrinter printer;
|
||||||
|
private final FastDateParser parser;
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Gets a formatter instance using the default pattern in the
|
||||||
|
* default locale.</p>
|
||||||
|
*
|
||||||
|
* @return a date/time formatter
|
||||||
|
*/
|
||||||
|
public static FastDateFormat getInstance() {
|
||||||
|
return cache.getInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Gets a formatter instance using the specified pattern in the
|
||||||
|
* default locale.</p>
|
||||||
|
*
|
||||||
|
* @param pattern {@link java.text.SimpleDateFormat} compatible
|
||||||
|
* pattern
|
||||||
|
* @return a pattern based date/time formatter
|
||||||
|
* @throws IllegalArgumentException if pattern is invalid
|
||||||
|
*/
|
||||||
|
public static FastDateFormat getInstance(final String pattern) {
|
||||||
|
return cache.getInstance(pattern, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Gets a formatter instance using the specified pattern and
|
||||||
|
* time zone.</p>
|
||||||
|
*
|
||||||
|
* @param pattern {@link java.text.SimpleDateFormat} compatible
|
||||||
|
* pattern
|
||||||
|
* @param timeZone optional time zone, overrides time zone of
|
||||||
|
* formatted date
|
||||||
|
* @return a pattern based date/time formatter
|
||||||
|
* @throws IllegalArgumentException if pattern is invalid
|
||||||
|
*/
|
||||||
|
public static FastDateFormat getInstance(final String pattern, final TimeZone timeZone) {
|
||||||
|
return cache.getInstance(pattern, timeZone, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Gets a formatter instance using the specified pattern and
|
||||||
|
* locale.</p>
|
||||||
|
*
|
||||||
|
* @param pattern {@link java.text.SimpleDateFormat} compatible
|
||||||
|
* pattern
|
||||||
|
* @param locale optional locale, overrides system locale
|
||||||
|
* @return a pattern based date/time formatter
|
||||||
|
* @throws IllegalArgumentException if pattern is invalid
|
||||||
|
*/
|
||||||
|
public static FastDateFormat getInstance(final String pattern, final Locale locale) {
|
||||||
|
return cache.getInstance(pattern, null, locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Gets a formatter instance using the specified pattern, time zone
|
||||||
|
* and locale.</p>
|
||||||
|
*
|
||||||
|
* @param pattern {@link java.text.SimpleDateFormat} compatible
|
||||||
|
* pattern
|
||||||
|
* @param timeZone optional time zone, overrides time zone of
|
||||||
|
* formatted date
|
||||||
|
* @param locale optional locale, overrides system locale
|
||||||
|
* @return a pattern based date/time formatter
|
||||||
|
* @throws IllegalArgumentException if pattern is invalid
|
||||||
|
* or {@code null}
|
||||||
|
*/
|
||||||
|
public static FastDateFormat getInstance(final String pattern, final TimeZone timeZone, final Locale locale) {
|
||||||
|
return cache.getInstance(pattern, timeZone, locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Gets a date formatter instance using the specified style in the
|
||||||
|
* default time zone and locale.</p>
|
||||||
|
*
|
||||||
|
* @param style date style: FULL, LONG, MEDIUM, or SHORT
|
||||||
|
* @return a localized standard date formatter
|
||||||
|
* @throws IllegalArgumentException if the Locale has no date
|
||||||
|
* pattern defined
|
||||||
|
* @since 2.1
|
||||||
|
*/
|
||||||
|
public static FastDateFormat getDateInstance(final int style) {
|
||||||
|
return cache.getDateInstance(style, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Gets a date formatter instance using the specified style and
|
||||||
|
* locale in the default time zone.</p>
|
||||||
|
*
|
||||||
|
* @param style date style: FULL, LONG, MEDIUM, or SHORT
|
||||||
|
* @param locale optional locale, overrides system locale
|
||||||
|
* @return a localized standard date formatter
|
||||||
|
* @throws IllegalArgumentException if the Locale has no date
|
||||||
|
* pattern defined
|
||||||
|
* @since 2.1
|
||||||
|
*/
|
||||||
|
public static FastDateFormat getDateInstance(final int style, final Locale locale) {
|
||||||
|
return cache.getDateInstance(style, null, locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Gets a date formatter instance using the specified style and
|
||||||
|
* time zone in the default locale.</p>
|
||||||
|
*
|
||||||
|
* @param style date style: FULL, LONG, MEDIUM, or SHORT
|
||||||
|
* @param timeZone optional time zone, overrides time zone of
|
||||||
|
* formatted date
|
||||||
|
* @return a localized standard date formatter
|
||||||
|
* @throws IllegalArgumentException if the Locale has no date
|
||||||
|
* pattern defined
|
||||||
|
* @since 2.1
|
||||||
|
*/
|
||||||
|
public static FastDateFormat getDateInstance(final int style, final TimeZone timeZone) {
|
||||||
|
return cache.getDateInstance(style, timeZone, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Gets a date formatter instance using the specified style, time
|
||||||
|
* zone and locale.</p>
|
||||||
|
*
|
||||||
|
* @param style date style: FULL, LONG, MEDIUM, or SHORT
|
||||||
|
* @param timeZone optional time zone, overrides time zone of
|
||||||
|
* formatted date
|
||||||
|
* @param locale optional locale, overrides system locale
|
||||||
|
* @return a localized standard date formatter
|
||||||
|
* @throws IllegalArgumentException if the Locale has no date
|
||||||
|
* pattern defined
|
||||||
|
*/
|
||||||
|
public static FastDateFormat getDateInstance(final int style, final TimeZone timeZone, final Locale locale) {
|
||||||
|
return cache.getDateInstance(style, timeZone, locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Gets a time formatter instance using the specified style in the
|
||||||
|
* default time zone and locale.</p>
|
||||||
|
*
|
||||||
|
* @param style time style: FULL, LONG, MEDIUM, or SHORT
|
||||||
|
* @return a localized standard time formatter
|
||||||
|
* @throws IllegalArgumentException if the Locale has no time
|
||||||
|
* pattern defined
|
||||||
|
* @since 2.1
|
||||||
|
*/
|
||||||
|
public static FastDateFormat getTimeInstance(final int style) {
|
||||||
|
return cache.getTimeInstance(style, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Gets a time formatter instance using the specified style and
|
||||||
|
* locale in the default time zone.</p>
|
||||||
|
*
|
||||||
|
* @param style time style: FULL, LONG, MEDIUM, or SHORT
|
||||||
|
* @param locale optional locale, overrides system locale
|
||||||
|
* @return a localized standard time formatter
|
||||||
|
* @throws IllegalArgumentException if the Locale has no time
|
||||||
|
* pattern defined
|
||||||
|
* @since 2.1
|
||||||
|
*/
|
||||||
|
public static FastDateFormat getTimeInstance(final int style, final Locale locale) {
|
||||||
|
return cache.getTimeInstance(style, null, locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Gets a time formatter instance using the specified style and
|
||||||
|
* time zone in the default locale.</p>
|
||||||
|
*
|
||||||
|
* @param style time style: FULL, LONG, MEDIUM, or SHORT
|
||||||
|
* @param timeZone optional time zone, overrides time zone of
|
||||||
|
* formatted time
|
||||||
|
* @return a localized standard time formatter
|
||||||
|
* @throws IllegalArgumentException if the Locale has no time
|
||||||
|
* pattern defined
|
||||||
|
* @since 2.1
|
||||||
|
*/
|
||||||
|
public static FastDateFormat getTimeInstance(final int style, final TimeZone timeZone) {
|
||||||
|
return cache.getTimeInstance(style, timeZone, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Gets a time formatter instance using the specified style, time
|
||||||
|
* zone and locale.</p>
|
||||||
|
*
|
||||||
|
* @param style time style: FULL, LONG, MEDIUM, or SHORT
|
||||||
|
* @param timeZone optional time zone, overrides time zone of
|
||||||
|
* formatted time
|
||||||
|
* @param locale optional locale, overrides system locale
|
||||||
|
* @return a localized standard time formatter
|
||||||
|
* @throws IllegalArgumentException if the Locale has no time
|
||||||
|
* pattern defined
|
||||||
|
*/
|
||||||
|
public static FastDateFormat getTimeInstance(final int style, final TimeZone timeZone, final Locale locale) {
|
||||||
|
return cache.getTimeInstance(style, timeZone, locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Gets a date/time formatter instance using the specified style
|
||||||
|
* in the default time zone and locale.</p>
|
||||||
|
*
|
||||||
|
* @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT
|
||||||
|
* @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT
|
||||||
|
* @return a localized standard date/time formatter
|
||||||
|
* @throws IllegalArgumentException if the Locale has no date/time
|
||||||
|
* pattern defined
|
||||||
|
* @since 2.1
|
||||||
|
*/
|
||||||
|
public static FastDateFormat getDateTimeInstance(final int dateStyle, final int timeStyle) {
|
||||||
|
return cache.getDateTimeInstance(dateStyle, timeStyle, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Gets a date/time formatter instance using the specified style and
|
||||||
|
* locale in the default time zone.</p>
|
||||||
|
*
|
||||||
|
* @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT
|
||||||
|
* @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT
|
||||||
|
* @param locale optional locale, overrides system locale
|
||||||
|
* @return a localized standard date/time formatter
|
||||||
|
* @throws IllegalArgumentException if the Locale has no date/time
|
||||||
|
* pattern defined
|
||||||
|
* @since 2.1
|
||||||
|
*/
|
||||||
|
public static FastDateFormat getDateTimeInstance(final int dateStyle, final int timeStyle, final Locale locale) {
|
||||||
|
return cache.getDateTimeInstance(dateStyle, timeStyle, null, locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Gets a date/time formatter instance using the specified style and
|
||||||
|
* time zone in the default locale.</p>
|
||||||
|
*
|
||||||
|
* @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT
|
||||||
|
* @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT
|
||||||
|
* @param timeZone optional time zone, overrides time zone of
|
||||||
|
* formatted date
|
||||||
|
* @return a localized standard date/time formatter
|
||||||
|
* @throws IllegalArgumentException if the Locale has no date/time
|
||||||
|
* pattern defined
|
||||||
|
* @since 2.1
|
||||||
|
*/
|
||||||
|
public static FastDateFormat getDateTimeInstance(final int dateStyle, final int timeStyle, final TimeZone timeZone) {
|
||||||
|
return getDateTimeInstance(dateStyle, timeStyle, timeZone, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Gets a date/time formatter instance using the specified style,
|
||||||
|
* time zone and locale.</p>
|
||||||
|
*
|
||||||
|
* @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT
|
||||||
|
* @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT
|
||||||
|
* @param timeZone optional time zone, overrides time zone of
|
||||||
|
* formatted date
|
||||||
|
* @param locale optional locale, overrides system locale
|
||||||
|
* @return a localized standard date/time formatter
|
||||||
|
* @throws IllegalArgumentException if the Locale has no date/time
|
||||||
|
* pattern defined
|
||||||
|
*/
|
||||||
|
public static FastDateFormat getDateTimeInstance(
|
||||||
|
final int dateStyle, final int timeStyle, final TimeZone timeZone, final Locale locale) {
|
||||||
|
return cache.getDateTimeInstance(dateStyle, timeStyle, timeZone, locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constructor
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Constructs a new FastDateFormat.</p>
|
||||||
|
*
|
||||||
|
* @param pattern {@link java.text.SimpleDateFormat} compatible pattern
|
||||||
|
* @param timeZone non-null time zone to use
|
||||||
|
* @param locale non-null locale to use
|
||||||
|
* @throws NullPointerException if pattern, timeZone, or locale is null.
|
||||||
|
*/
|
||||||
|
protected FastDateFormat(final String pattern, final TimeZone timeZone, final Locale locale) {
|
||||||
|
this(pattern, timeZone, locale, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constructor
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Constructs a new FastDateFormat.</p>
|
||||||
|
*
|
||||||
|
* @param pattern {@link java.text.SimpleDateFormat} compatible pattern
|
||||||
|
* @param timeZone non-null time zone to use
|
||||||
|
* @param locale non-null locale to use
|
||||||
|
* @param centuryStart The start of the 100 year period to use as the "default century" for 2 digit year parsing. If centuryStart is null, defaults to now - 80 years
|
||||||
|
* @throws NullPointerException if pattern, timeZone, or locale is null.
|
||||||
|
*/
|
||||||
|
protected FastDateFormat(final String pattern, final TimeZone timeZone, final Locale locale, final Date centuryStart) {
|
||||||
|
printer = new FastDatePrinter(pattern, timeZone, locale);
|
||||||
|
parser = new FastDateParser(pattern, timeZone, locale, centuryStart);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format methods
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Formats a {@code Date}, {@code Calendar} or
|
||||||
|
* {@code Long} (milliseconds) object.</p>
|
||||||
|
*
|
||||||
|
* @param obj the object to format
|
||||||
|
* @param toAppendTo the buffer to append to
|
||||||
|
* @param pos the position - ignored
|
||||||
|
* @return the buffer passed in
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public StringBuffer format(final Object obj, final StringBuffer toAppendTo, final FieldPosition pos) {
|
||||||
|
return printer.format(obj, toAppendTo, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Formats a millisecond {@code long} value.</p>
|
||||||
|
*
|
||||||
|
* @param millis the millisecond value to format
|
||||||
|
* @return the formatted string
|
||||||
|
* @since 2.1
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String format(final long millis) {
|
||||||
|
return printer.format(millis);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Formats a {@code Date} object using a {@code GregorianCalendar}.</p>
|
||||||
|
*
|
||||||
|
* @param date the date to format
|
||||||
|
* @return the formatted string
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String format(final Date date) {
|
||||||
|
return printer.format(date);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Formats a {@code Calendar} object.</p>
|
||||||
|
*
|
||||||
|
* @param calendar the calendar to format
|
||||||
|
* @return the formatted string
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String format(final Calendar calendar) {
|
||||||
|
return printer.format(calendar);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Formats a millisecond {@code long} value into the
|
||||||
|
* supplied {@code StringBuffer}.</p>
|
||||||
|
*
|
||||||
|
* @param millis the millisecond value to format
|
||||||
|
* @param buf the buffer to format into
|
||||||
|
* @return the specified string buffer
|
||||||
|
* @since 2.1
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public StringBuffer format(final long millis, final StringBuffer buf) {
|
||||||
|
return printer.format(millis, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Formats a {@code Date} object into the
|
||||||
|
* supplied {@code StringBuffer} using a {@code GregorianCalendar}.</p>
|
||||||
|
*
|
||||||
|
* @param date the date to format
|
||||||
|
* @param buf the buffer to format into
|
||||||
|
* @return the specified string buffer
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public StringBuffer format(final Date date, final StringBuffer buf) {
|
||||||
|
return printer.format(date, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Formats a {@code Calendar} object into the
|
||||||
|
* supplied {@code StringBuffer}.</p>
|
||||||
|
*
|
||||||
|
* @param calendar the calendar to format
|
||||||
|
* @param buf the buffer to format into
|
||||||
|
* @return the specified string buffer
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public StringBuffer format(final Calendar calendar, final StringBuffer buf) {
|
||||||
|
return printer.format(calendar, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parsing
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see DateParser#parse(java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Date parse(final String source) throws ParseException {
|
||||||
|
return parser.parse(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see DateParser#parse(java.lang.String, java.text.ParsePosition)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Date parse(final String source, final ParsePosition pos) {
|
||||||
|
return parser.parse(source, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see java.text.Format#parseObject(java.lang.String, java.text.ParsePosition)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Object parseObject(final String source, final ParsePosition pos) {
|
||||||
|
return parser.parseObject(source, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Accessors
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Gets the pattern used by this formatter.</p>
|
||||||
|
*
|
||||||
|
* @return the pattern, {@link java.text.SimpleDateFormat} compatible
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getPattern() {
|
||||||
|
return printer.getPattern();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Gets the time zone used by this formatter.</p>
|
||||||
|
* <p/>
|
||||||
|
* <p>This zone is always used for {@code Date} formatting. </p>
|
||||||
|
*
|
||||||
|
* @return the time zone
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public TimeZone getTimeZone() {
|
||||||
|
return printer.getTimeZone();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Gets the locale used by this formatter.</p>
|
||||||
|
*
|
||||||
|
* @return the locale
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Locale getLocale() {
|
||||||
|
return printer.getLocale();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Gets an estimate for the maximum string length that the
|
||||||
|
* formatter will produce.</p>
|
||||||
|
* <p/>
|
||||||
|
* <p>The actual formatted length will almost always be less than or
|
||||||
|
* equal to this amount.</p>
|
||||||
|
*
|
||||||
|
* @return the maximum formatted length
|
||||||
|
*/
|
||||||
|
public int getMaxLengthEstimate() {
|
||||||
|
return printer.getMaxLengthEstimate();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Basics
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Compares two objects for equality.</p>
|
||||||
|
*
|
||||||
|
* @param obj the object to compare to
|
||||||
|
* @return {@code true} if equal
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean equals(final Object obj) {
|
||||||
|
if (!(obj instanceof FastDateFormat)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final FastDateFormat other = (FastDateFormat) obj;
|
||||||
|
// no need to check parser, as it has same invariants as printer
|
||||||
|
return printer.equals(other.printer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Returns a hashcode compatible with equals.</p>
|
||||||
|
*
|
||||||
|
* @return a hashcode compatible with equals
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return printer.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Gets a debugging string version of this formatter.</p>
|
||||||
|
*
|
||||||
|
* @return a debugging string
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "FastDateFormat[" + printer.getPattern() + "," + printer.getLocale() + "," + printer.getTimeZone().getID() + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Performs the formatting by applying the rules to the
|
||||||
|
* specified calendar.</p>
|
||||||
|
*
|
||||||
|
* @param calendar the calendar to format
|
||||||
|
* @param buf the buffer to format into
|
||||||
|
* @return the specified string buffer
|
||||||
|
*/
|
||||||
|
protected StringBuffer applyRules(final Calendar calendar, final StringBuffer buf) {
|
||||||
|
return printer.applyRules(calendar, buf);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,873 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.telegram.android.time;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.ObjectInputStream;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.text.DateFormatSymbols;
|
||||||
|
import java.text.ParseException;
|
||||||
|
import java.text.ParsePosition;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.SortedMap;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.ConcurrentMap;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>FastDateParser is a fast and thread-safe version of
|
||||||
|
* {@link java.text.SimpleDateFormat}.</p>
|
||||||
|
*
|
||||||
|
* <p>This class can be used as a direct replacement for
|
||||||
|
* <code>SimpleDateFormat</code> in most parsing situations.
|
||||||
|
* This class is especially useful in multi-threaded server environments.
|
||||||
|
* <code>SimpleDateFormat</code> is not thread-safe in any JDK version,
|
||||||
|
* nor will it be as Sun has closed the
|
||||||
|
* <a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4228335">bug</a>/RFE.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <p>Only parsing is supported, but all patterns are compatible with
|
||||||
|
* SimpleDateFormat.</p>
|
||||||
|
*
|
||||||
|
* <p>Timing tests indicate this class is as about as fast as SimpleDateFormat
|
||||||
|
* in single thread applications and about 25% faster in multi-thread applications.</p>
|
||||||
|
*
|
||||||
|
* @version $Id: FastDateParser.java 1572877 2014-02-28 08:42:25Z britter $
|
||||||
|
* @since 3.2
|
||||||
|
*/
|
||||||
|
public class FastDateParser implements DateParser, Serializable {
|
||||||
|
/**
|
||||||
|
* Required for serialization support.
|
||||||
|
*
|
||||||
|
* @see java.io.Serializable
|
||||||
|
*/
|
||||||
|
private static final long serialVersionUID = 2L;
|
||||||
|
|
||||||
|
static final Locale JAPANESE_IMPERIAL = new Locale("ja", "JP", "JP");
|
||||||
|
|
||||||
|
// defining fields
|
||||||
|
private final String pattern;
|
||||||
|
private final TimeZone timeZone;
|
||||||
|
private final Locale locale;
|
||||||
|
private final int century;
|
||||||
|
private final int startYear;
|
||||||
|
|
||||||
|
// derived fields
|
||||||
|
private transient Pattern parsePattern;
|
||||||
|
private transient Strategy[] strategies;
|
||||||
|
|
||||||
|
// dynamic fields to communicate with Strategy
|
||||||
|
private transient String currentFormatField;
|
||||||
|
private transient Strategy nextStrategy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Constructs a new FastDateParser.</p>
|
||||||
|
*
|
||||||
|
* @param pattern non-null {@link java.text.SimpleDateFormat} compatible
|
||||||
|
* pattern
|
||||||
|
* @param timeZone non-null time zone to use
|
||||||
|
* @param locale non-null locale
|
||||||
|
*/
|
||||||
|
protected FastDateParser(final String pattern, final TimeZone timeZone, final Locale locale) {
|
||||||
|
this(pattern, timeZone, locale, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Constructs a new FastDateParser.</p>
|
||||||
|
*
|
||||||
|
* @param pattern non-null {@link java.text.SimpleDateFormat} compatible
|
||||||
|
* pattern
|
||||||
|
* @param timeZone non-null time zone to use
|
||||||
|
* @param locale non-null locale
|
||||||
|
* @param centuryStart The start of the century for 2 digit year parsing
|
||||||
|
* @since 3.3
|
||||||
|
*/
|
||||||
|
protected FastDateParser(final String pattern, final TimeZone timeZone, final Locale locale, final Date centuryStart) {
|
||||||
|
this.pattern = pattern;
|
||||||
|
this.timeZone = timeZone;
|
||||||
|
this.locale = locale;
|
||||||
|
|
||||||
|
final Calendar definingCalendar = Calendar.getInstance(timeZone, locale);
|
||||||
|
int centuryStartYear;
|
||||||
|
if (centuryStart != null) {
|
||||||
|
definingCalendar.setTime(centuryStart);
|
||||||
|
centuryStartYear = definingCalendar.get(Calendar.YEAR);
|
||||||
|
} else if (locale.equals(JAPANESE_IMPERIAL)) {
|
||||||
|
centuryStartYear = 0;
|
||||||
|
} else {
|
||||||
|
// from 80 years ago to 20 years from now
|
||||||
|
definingCalendar.setTime(new Date());
|
||||||
|
centuryStartYear = definingCalendar.get(Calendar.YEAR) - 80;
|
||||||
|
}
|
||||||
|
century = centuryStartYear / 100 * 100;
|
||||||
|
startYear = centuryStartYear - century;
|
||||||
|
|
||||||
|
init(definingCalendar);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize derived fields from defining fields.
|
||||||
|
* This is called from constructor and from readObject (de-serialization)
|
||||||
|
*
|
||||||
|
* @param definingCalendar the {@link java.util.Calendar} instance used to initialize this FastDateParser
|
||||||
|
*/
|
||||||
|
private void init(Calendar definingCalendar) {
|
||||||
|
|
||||||
|
final StringBuilder regex = new StringBuilder();
|
||||||
|
final List<Strategy> collector = new ArrayList<Strategy>();
|
||||||
|
|
||||||
|
final Matcher patternMatcher = formatPattern.matcher(pattern);
|
||||||
|
if (!patternMatcher.lookingAt()) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Illegal pattern character '" + pattern.charAt(patternMatcher.regionStart()) + "'");
|
||||||
|
}
|
||||||
|
|
||||||
|
currentFormatField = patternMatcher.group();
|
||||||
|
Strategy currentStrategy = getStrategy(currentFormatField, definingCalendar);
|
||||||
|
for (; ; ) {
|
||||||
|
patternMatcher.region(patternMatcher.end(), patternMatcher.regionEnd());
|
||||||
|
if (!patternMatcher.lookingAt()) {
|
||||||
|
nextStrategy = null;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
final String nextFormatField = patternMatcher.group();
|
||||||
|
nextStrategy = getStrategy(nextFormatField, definingCalendar);
|
||||||
|
if (currentStrategy.addRegex(this, regex)) {
|
||||||
|
collector.add(currentStrategy);
|
||||||
|
}
|
||||||
|
currentFormatField = nextFormatField;
|
||||||
|
currentStrategy = nextStrategy;
|
||||||
|
}
|
||||||
|
if (patternMatcher.regionStart() != patternMatcher.regionEnd()) {
|
||||||
|
throw new IllegalArgumentException("Failed to parse \"" + pattern + "\" ; gave up at index " + patternMatcher.regionStart());
|
||||||
|
}
|
||||||
|
if (currentStrategy.addRegex(this, regex)) {
|
||||||
|
collector.add(currentStrategy);
|
||||||
|
}
|
||||||
|
currentFormatField = null;
|
||||||
|
strategies = collector.toArray(new Strategy[collector.size()]);
|
||||||
|
parsePattern = Pattern.compile(regex.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Accessors
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see org.apache.commons.lang3.time.DateParser#getPattern()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getPattern() {
|
||||||
|
return pattern;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see org.apache.commons.lang3.time.DateParser#getTimeZone()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public TimeZone getTimeZone() {
|
||||||
|
return timeZone;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see org.apache.commons.lang3.time.DateParser#getLocale()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Locale getLocale() {
|
||||||
|
return locale;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the generated pattern (for testing purposes).
|
||||||
|
*
|
||||||
|
* @return the generated pattern
|
||||||
|
*/
|
||||||
|
Pattern getParsePattern() {
|
||||||
|
return parsePattern;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Basics
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Compare another object for equality with this object.</p>
|
||||||
|
*
|
||||||
|
* @param obj the object to compare to
|
||||||
|
* @return <code>true</code>if equal to this instance
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean equals(final Object obj) {
|
||||||
|
if (!(obj instanceof FastDateParser)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final FastDateParser other = (FastDateParser) obj;
|
||||||
|
return pattern.equals(other.pattern)
|
||||||
|
&& timeZone.equals(other.timeZone)
|
||||||
|
&& locale.equals(other.locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Return a hashcode compatible with equals.</p>
|
||||||
|
*
|
||||||
|
* @return a hashcode compatible with equals
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return pattern.hashCode() + 13 * (timeZone.hashCode() + 13 * locale.hashCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Get a string version of this formatter.</p>
|
||||||
|
*
|
||||||
|
* @return a debugging string
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "FastDateParser[" + pattern + "," + locale + "," + timeZone.getID() + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Serializing
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create the object after serialization. This implementation reinitializes the
|
||||||
|
* transient properties.
|
||||||
|
*
|
||||||
|
* @param in ObjectInputStream from which the object is being deserialized.
|
||||||
|
* @throws IOException if there is an IO issue.
|
||||||
|
* @throws ClassNotFoundException if a class cannot be found.
|
||||||
|
*/
|
||||||
|
private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||||
|
in.defaultReadObject();
|
||||||
|
|
||||||
|
final Calendar definingCalendar = Calendar.getInstance(timeZone, locale);
|
||||||
|
init(definingCalendar);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see org.apache.commons.lang3.time.DateParser#parseObject(java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Object parseObject(final String source) throws ParseException {
|
||||||
|
return parse(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see org.apache.commons.lang3.time.DateParser#parse(java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Date parse(final String source) throws ParseException {
|
||||||
|
final Date date = parse(source, new ParsePosition(0));
|
||||||
|
if (date == null) {
|
||||||
|
// Add a note re supported date range
|
||||||
|
if (locale.equals(JAPANESE_IMPERIAL)) {
|
||||||
|
throw new ParseException(
|
||||||
|
"(The " + locale + " locale does not support dates before 1868 AD)\n" +
|
||||||
|
"Unparseable date: \"" + source + "\" does not match " + parsePattern.pattern(), 0);
|
||||||
|
}
|
||||||
|
throw new ParseException("Unparseable date: \"" + source + "\" does not match " + parsePattern.pattern(), 0);
|
||||||
|
}
|
||||||
|
return date;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see org.apache.commons.lang3.time.DateParser#parseObject(java.lang.String, java.text.ParsePosition)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Object parseObject(final String source, final ParsePosition pos) {
|
||||||
|
return parse(source, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see org.apache.commons.lang3.time.DateParser#parse(java.lang.String, java.text.ParsePosition)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Date parse(final String source, final ParsePosition pos) {
|
||||||
|
final int offset = pos.getIndex();
|
||||||
|
final Matcher matcher = parsePattern.matcher(source.substring(offset));
|
||||||
|
if (!matcher.lookingAt()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// timing tests indicate getting new instance is 19% faster than cloning
|
||||||
|
final Calendar cal = Calendar.getInstance(timeZone, locale);
|
||||||
|
cal.clear();
|
||||||
|
|
||||||
|
for (int i = 0; i < strategies.length; ) {
|
||||||
|
final Strategy strategy = strategies[i++];
|
||||||
|
strategy.setCalendar(this, cal, matcher.group(i));
|
||||||
|
}
|
||||||
|
pos.setIndex(offset + matcher.end());
|
||||||
|
return cal.getTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Support for strategies
|
||||||
|
//-----------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Escape constant fields into regular expression
|
||||||
|
*
|
||||||
|
* @param regex The destination regex
|
||||||
|
* @param value The source field
|
||||||
|
* @param unquote If true, replace two success quotes ('') with single quote (')
|
||||||
|
* @return The <code>StringBuilder</code>
|
||||||
|
*/
|
||||||
|
private static StringBuilder escapeRegex(final StringBuilder regex, final String value, final boolean unquote) {
|
||||||
|
regex.append("\\Q");
|
||||||
|
for (int i = 0; i < value.length(); ++i) {
|
||||||
|
char c = value.charAt(i);
|
||||||
|
switch (c) {
|
||||||
|
case '\'':
|
||||||
|
if (unquote) {
|
||||||
|
if (++i == value.length()) {
|
||||||
|
return regex;
|
||||||
|
}
|
||||||
|
c = value.charAt(i);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '\\':
|
||||||
|
if (++i == value.length()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* If we have found \E, we replace it with \E\\E\Q, i.e. we stop the quoting,
|
||||||
|
* quote the \ in \E, then restart the quoting.
|
||||||
|
*
|
||||||
|
* Otherwise we just output the two characters.
|
||||||
|
* In each case the initial \ needs to be output and the final char is done at the end
|
||||||
|
*/
|
||||||
|
regex.append(c); // we always want the original \
|
||||||
|
c = value.charAt(i); // Is it followed by E ?
|
||||||
|
if (c == 'E') { // \E detected
|
||||||
|
regex.append("E\\\\E\\"); // see comment above
|
||||||
|
c = 'Q'; // appended below
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
regex.append(c);
|
||||||
|
}
|
||||||
|
regex.append("\\E");
|
||||||
|
return regex;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String[] getDisplayNameArray(int field, boolean isLong, Locale locale) {
|
||||||
|
DateFormatSymbols dfs = new DateFormatSymbols(locale);
|
||||||
|
switch (field) {
|
||||||
|
case Calendar.AM_PM:
|
||||||
|
return dfs.getAmPmStrings();
|
||||||
|
case Calendar.DAY_OF_WEEK:
|
||||||
|
return isLong ? dfs.getWeekdays() : dfs.getShortWeekdays();
|
||||||
|
case Calendar.ERA:
|
||||||
|
return dfs.getEras();
|
||||||
|
case Calendar.MONTH:
|
||||||
|
return isLong ? dfs.getMonths() : dfs.getShortMonths();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void insertValuesInMap(Map<String, Integer> map, String[] values) {
|
||||||
|
if (values == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < values.length; ++i) {
|
||||||
|
if (values[i] != null && values[i].length() > 0) {
|
||||||
|
map.put(values[i], i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Map<String, Integer> getDisplayNames(int field, Locale locale) {
|
||||||
|
Map<String, Integer> result = new HashMap<String, Integer>();
|
||||||
|
insertValuesInMap(result, getDisplayNameArray(field, false, locale));
|
||||||
|
insertValuesInMap(result, getDisplayNameArray(field, true, locale));
|
||||||
|
return result.isEmpty() ? null : result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the short and long values displayed for a field
|
||||||
|
*
|
||||||
|
* @param field The field of interest
|
||||||
|
* @param definingCalendar The calendar to obtain the short and long values
|
||||||
|
* @param locale The locale of display names
|
||||||
|
* @return A Map of the field key / value pairs
|
||||||
|
*/
|
||||||
|
private static Map<String, Integer> getDisplayNames(final int field, final Calendar definingCalendar, final Locale locale) {
|
||||||
|
return getDisplayNames(field, locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adjust dates to be within appropriate century
|
||||||
|
*
|
||||||
|
* @param twoDigitYear The year to adjust
|
||||||
|
* @return A value between centuryStart(inclusive) to centuryStart+100(exclusive)
|
||||||
|
*/
|
||||||
|
private int adjustYear(final int twoDigitYear) {
|
||||||
|
int trial = century + twoDigitYear;
|
||||||
|
return twoDigitYear >= startYear ? trial : trial + 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is the next field a number?
|
||||||
|
*
|
||||||
|
* @return true, if next field will be a number
|
||||||
|
*/
|
||||||
|
boolean isNextNumber() {
|
||||||
|
return nextStrategy != null && nextStrategy.isNumber();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* What is the width of the current field?
|
||||||
|
*
|
||||||
|
* @return The number of characters in the current format field
|
||||||
|
*/
|
||||||
|
int getFieldWidth() {
|
||||||
|
return currentFormatField.length();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A strategy to parse a single field from the parsing pattern
|
||||||
|
*/
|
||||||
|
private static abstract class Strategy {
|
||||||
|
/**
|
||||||
|
* Is this field a number?
|
||||||
|
* The default implementation returns false.
|
||||||
|
*
|
||||||
|
* @return true, if field is a number
|
||||||
|
*/
|
||||||
|
boolean isNumber() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the Calendar with the parsed field.
|
||||||
|
* <p/>
|
||||||
|
* The default implementation does nothing.
|
||||||
|
*
|
||||||
|
* @param parser The parser calling this strategy
|
||||||
|
* @param cal The <code>Calendar</code> to set
|
||||||
|
* @param value The parsed field to translate and set in cal
|
||||||
|
*/
|
||||||
|
void setCalendar(final FastDateParser parser, final Calendar cal, final String value) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a <code>Pattern</code> regular expression to the <code>StringBuilder</code>
|
||||||
|
* which will accept this field
|
||||||
|
*
|
||||||
|
* @param parser The parser calling this strategy
|
||||||
|
* @param regex The <code>StringBuilder</code> to append to
|
||||||
|
* @return true, if this field will set the calendar;
|
||||||
|
* false, if this field is a constant value
|
||||||
|
*/
|
||||||
|
abstract boolean addRegex(FastDateParser parser, StringBuilder regex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A <code>Pattern</code> to parse the user supplied SimpleDateFormat pattern
|
||||||
|
*/
|
||||||
|
private static final Pattern formatPattern = Pattern.compile(
|
||||||
|
"D+|E+|F+|G+|H+|K+|M+|S+|W+|Z+|a+|d+|h+|k+|m+|s+|w+|y+|z+|''|'[^']++(''[^']*+)*+'|[^'A-Za-z]++");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtain a Strategy given a field from a SimpleDateFormat pattern
|
||||||
|
*
|
||||||
|
* @param formatField A sub-sequence of the SimpleDateFormat pattern
|
||||||
|
* @param definingCalendar The calendar to obtain the short and long values
|
||||||
|
* @return The Strategy that will handle parsing for the field
|
||||||
|
*/
|
||||||
|
private Strategy getStrategy(final String formatField, final Calendar definingCalendar) {
|
||||||
|
switch (formatField.charAt(0)) {
|
||||||
|
case '\'':
|
||||||
|
if (formatField.length() > 2) {
|
||||||
|
return new CopyQuotedStrategy(formatField.substring(1, formatField.length() - 1));
|
||||||
|
}
|
||||||
|
//$FALL-THROUGH$
|
||||||
|
default:
|
||||||
|
return new CopyQuotedStrategy(formatField);
|
||||||
|
case 'D':
|
||||||
|
return DAY_OF_YEAR_STRATEGY;
|
||||||
|
case 'E':
|
||||||
|
return getLocaleSpecificStrategy(Calendar.DAY_OF_WEEK, definingCalendar);
|
||||||
|
case 'F':
|
||||||
|
return DAY_OF_WEEK_IN_MONTH_STRATEGY;
|
||||||
|
case 'G':
|
||||||
|
return getLocaleSpecificStrategy(Calendar.ERA, definingCalendar);
|
||||||
|
case 'H':
|
||||||
|
return MODULO_HOUR_OF_DAY_STRATEGY;
|
||||||
|
case 'K':
|
||||||
|
return HOUR_STRATEGY;
|
||||||
|
case 'M':
|
||||||
|
return formatField.length() >= 3 ? getLocaleSpecificStrategy(Calendar.MONTH, definingCalendar) : NUMBER_MONTH_STRATEGY;
|
||||||
|
case 'S':
|
||||||
|
return MILLISECOND_STRATEGY;
|
||||||
|
case 'W':
|
||||||
|
return WEEK_OF_MONTH_STRATEGY;
|
||||||
|
case 'a':
|
||||||
|
return getLocaleSpecificStrategy(Calendar.AM_PM, definingCalendar);
|
||||||
|
case 'd':
|
||||||
|
return DAY_OF_MONTH_STRATEGY;
|
||||||
|
case 'h':
|
||||||
|
return MODULO_HOUR_STRATEGY;
|
||||||
|
case 'k':
|
||||||
|
return HOUR_OF_DAY_STRATEGY;
|
||||||
|
case 'm':
|
||||||
|
return MINUTE_STRATEGY;
|
||||||
|
case 's':
|
||||||
|
return SECOND_STRATEGY;
|
||||||
|
case 'w':
|
||||||
|
return WEEK_OF_YEAR_STRATEGY;
|
||||||
|
case 'y':
|
||||||
|
return formatField.length() > 2 ? LITERAL_YEAR_STRATEGY : ABBREVIATED_YEAR_STRATEGY;
|
||||||
|
case 'Z':
|
||||||
|
case 'z':
|
||||||
|
return getLocaleSpecificStrategy(Calendar.ZONE_OFFSET, definingCalendar);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked") // OK because we are creating an array with no entries
|
||||||
|
private static final ConcurrentMap<Locale, Strategy>[] caches = new ConcurrentMap[Calendar.FIELD_COUNT];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a cache of Strategies for a particular field
|
||||||
|
*
|
||||||
|
* @param field The Calendar field
|
||||||
|
* @return a cache of Locale to Strategy
|
||||||
|
*/
|
||||||
|
private static ConcurrentMap<Locale, Strategy> getCache(final int field) {
|
||||||
|
synchronized (caches) {
|
||||||
|
if (caches[field] == null) {
|
||||||
|
caches[field] = new ConcurrentHashMap<Locale, Strategy>(3);
|
||||||
|
}
|
||||||
|
return caches[field];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a Strategy that parses a Text field
|
||||||
|
*
|
||||||
|
* @param field The Calendar field
|
||||||
|
* @param definingCalendar The calendar to obtain the short and long values
|
||||||
|
* @return a TextStrategy for the field and Locale
|
||||||
|
*/
|
||||||
|
private Strategy getLocaleSpecificStrategy(final int field, final Calendar definingCalendar) {
|
||||||
|
final ConcurrentMap<Locale, Strategy> cache = getCache(field);
|
||||||
|
Strategy strategy = cache.get(locale);
|
||||||
|
if (strategy == null) {
|
||||||
|
strategy = field == Calendar.ZONE_OFFSET
|
||||||
|
? new TimeZoneStrategy(locale)
|
||||||
|
: new TextStrategy(field, definingCalendar, locale);
|
||||||
|
final Strategy inCache = cache.putIfAbsent(locale, strategy);
|
||||||
|
if (inCache != null) {
|
||||||
|
return inCache;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return strategy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A strategy that copies the static or quoted field in the parsing pattern
|
||||||
|
*/
|
||||||
|
private static class CopyQuotedStrategy extends Strategy {
|
||||||
|
private final String formatField;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a Strategy that ensures the formatField has literal text
|
||||||
|
*
|
||||||
|
* @param formatField The literal text to match
|
||||||
|
*/
|
||||||
|
CopyQuotedStrategy(final String formatField) {
|
||||||
|
this.formatField = formatField;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
boolean isNumber() {
|
||||||
|
char c = formatField.charAt(0);
|
||||||
|
if (c == '\'') {
|
||||||
|
c = formatField.charAt(1);
|
||||||
|
}
|
||||||
|
return Character.isDigit(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
boolean addRegex(final FastDateParser parser, final StringBuilder regex) {
|
||||||
|
escapeRegex(regex, formatField, true);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A strategy that handles a text field in the parsing pattern
|
||||||
|
*/
|
||||||
|
private static class TextStrategy extends Strategy {
|
||||||
|
private final int field;
|
||||||
|
private final Map<String, Integer> keyValues;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a Strategy that parses a Text field
|
||||||
|
*
|
||||||
|
* @param field The Calendar field
|
||||||
|
* @param definingCalendar The Calendar to use
|
||||||
|
* @param locale The Locale to use
|
||||||
|
*/
|
||||||
|
TextStrategy(final int field, final Calendar definingCalendar, final Locale locale) {
|
||||||
|
this.field = field;
|
||||||
|
this.keyValues = getDisplayNames(field, definingCalendar, locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
boolean addRegex(final FastDateParser parser, final StringBuilder regex) {
|
||||||
|
regex.append('(');
|
||||||
|
for (final String textKeyValue : keyValues.keySet()) {
|
||||||
|
escapeRegex(regex, textKeyValue, false).append('|');
|
||||||
|
}
|
||||||
|
regex.setCharAt(regex.length() - 1, ')');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
void setCalendar(final FastDateParser parser, final Calendar cal, final String value) {
|
||||||
|
final Integer iVal = keyValues.get(value);
|
||||||
|
if (iVal == null) {
|
||||||
|
final StringBuilder sb = new StringBuilder(value);
|
||||||
|
sb.append(" not in (");
|
||||||
|
for (final String textKeyValue : keyValues.keySet()) {
|
||||||
|
sb.append(textKeyValue).append(' ');
|
||||||
|
}
|
||||||
|
sb.setCharAt(sb.length() - 1, ')');
|
||||||
|
throw new IllegalArgumentException(sb.toString());
|
||||||
|
}
|
||||||
|
cal.set(field, iVal.intValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A strategy that handles a number field in the parsing pattern
|
||||||
|
*/
|
||||||
|
private static class NumberStrategy extends Strategy {
|
||||||
|
private final int field;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a Strategy that parses a Number field
|
||||||
|
*
|
||||||
|
* @param field The Calendar field
|
||||||
|
*/
|
||||||
|
NumberStrategy(final int field) {
|
||||||
|
this.field = field;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
boolean isNumber() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
boolean addRegex(final FastDateParser parser, final StringBuilder regex) {
|
||||||
|
// See LANG-954: We use {Nd} rather than {IsNd} because Android does not support the Is prefix
|
||||||
|
if (parser.isNextNumber()) {
|
||||||
|
regex.append("(\\p{Nd}{").append(parser.getFieldWidth()).append("}+)");
|
||||||
|
} else {
|
||||||
|
regex.append("(\\p{Nd}++)");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
void setCalendar(final FastDateParser parser, final Calendar cal, final String value) {
|
||||||
|
cal.set(field, modify(Integer.parseInt(value)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make any modifications to parsed integer
|
||||||
|
*
|
||||||
|
* @param iValue The parsed integer
|
||||||
|
* @return The modified value
|
||||||
|
*/
|
||||||
|
int modify(final int iValue) {
|
||||||
|
return iValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Strategy ABBREVIATED_YEAR_STRATEGY = new NumberStrategy(Calendar.YEAR) {
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
void setCalendar(final FastDateParser parser, final Calendar cal, final String value) {
|
||||||
|
int iValue = Integer.parseInt(value);
|
||||||
|
if (iValue < 100) {
|
||||||
|
iValue = parser.adjustYear(iValue);
|
||||||
|
}
|
||||||
|
cal.set(Calendar.YEAR, iValue);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A strategy that handles a timezone field in the parsing pattern
|
||||||
|
*/
|
||||||
|
private static class TimeZoneStrategy extends Strategy {
|
||||||
|
|
||||||
|
private final String validTimeZoneChars;
|
||||||
|
private final SortedMap<String, TimeZone> tzNames = new TreeMap<String, TimeZone>(String.CASE_INSENSITIVE_ORDER);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Index of zone id
|
||||||
|
*/
|
||||||
|
private static final int ID = 0;
|
||||||
|
/**
|
||||||
|
* Index of the long name of zone in standard time
|
||||||
|
*/
|
||||||
|
private static final int LONG_STD = 1;
|
||||||
|
/**
|
||||||
|
* Index of the short name of zone in standard time
|
||||||
|
*/
|
||||||
|
private static final int SHORT_STD = 2;
|
||||||
|
/**
|
||||||
|
* Index of the long name of zone in daylight saving time
|
||||||
|
*/
|
||||||
|
private static final int LONG_DST = 3;
|
||||||
|
/**
|
||||||
|
* Index of the short name of zone in daylight saving time
|
||||||
|
*/
|
||||||
|
private static final int SHORT_DST = 4;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a Strategy that parses a TimeZone
|
||||||
|
*
|
||||||
|
* @param locale The Locale
|
||||||
|
*/
|
||||||
|
TimeZoneStrategy(final Locale locale) {
|
||||||
|
final String[][] zones = DateFormatSymbols.getInstance(locale).getZoneStrings();
|
||||||
|
for (String[] zone : zones) {
|
||||||
|
if (zone[ID].startsWith("GMT")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
final TimeZone tz = TimeZone.getTimeZone(zone[ID]);
|
||||||
|
if (!tzNames.containsKey(zone[LONG_STD])) {
|
||||||
|
tzNames.put(zone[LONG_STD], tz);
|
||||||
|
}
|
||||||
|
if (!tzNames.containsKey(zone[SHORT_STD])) {
|
||||||
|
tzNames.put(zone[SHORT_STD], tz);
|
||||||
|
}
|
||||||
|
if (tz.useDaylightTime()) {
|
||||||
|
if (!tzNames.containsKey(zone[LONG_DST])) {
|
||||||
|
tzNames.put(zone[LONG_DST], tz);
|
||||||
|
}
|
||||||
|
if (!tzNames.containsKey(zone[SHORT_DST])) {
|
||||||
|
tzNames.put(zone[SHORT_DST], tz);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append("(GMT[+\\-]\\d{0,1}\\d{2}|[+\\-]\\d{2}:?\\d{2}|");
|
||||||
|
for (final String id : tzNames.keySet()) {
|
||||||
|
escapeRegex(sb, id, false).append('|');
|
||||||
|
}
|
||||||
|
sb.setCharAt(sb.length() - 1, ')');
|
||||||
|
validTimeZoneChars = sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
boolean addRegex(final FastDateParser parser, final StringBuilder regex) {
|
||||||
|
regex.append(validTimeZoneChars);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
void setCalendar(final FastDateParser parser, final Calendar cal, final String value) {
|
||||||
|
TimeZone tz;
|
||||||
|
if (value.charAt(0) == '+' || value.charAt(0) == '-') {
|
||||||
|
tz = TimeZone.getTimeZone("GMT" + value);
|
||||||
|
} else if (value.startsWith("GMT")) {
|
||||||
|
tz = TimeZone.getTimeZone(value);
|
||||||
|
} else {
|
||||||
|
tz = tzNames.get(value);
|
||||||
|
if (tz == null) {
|
||||||
|
throw new IllegalArgumentException(value + " is not a supported timezone name");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cal.setTimeZone(tz);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Strategy NUMBER_MONTH_STRATEGY = new NumberStrategy(Calendar.MONTH) {
|
||||||
|
@Override
|
||||||
|
int modify(final int iValue) {
|
||||||
|
return iValue - 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
private static final Strategy LITERAL_YEAR_STRATEGY = new NumberStrategy(Calendar.YEAR);
|
||||||
|
private static final Strategy WEEK_OF_YEAR_STRATEGY = new NumberStrategy(Calendar.WEEK_OF_YEAR);
|
||||||
|
private static final Strategy WEEK_OF_MONTH_STRATEGY = new NumberStrategy(Calendar.WEEK_OF_MONTH);
|
||||||
|
private static final Strategy DAY_OF_YEAR_STRATEGY = new NumberStrategy(Calendar.DAY_OF_YEAR);
|
||||||
|
private static final Strategy DAY_OF_MONTH_STRATEGY = new NumberStrategy(Calendar.DAY_OF_MONTH);
|
||||||
|
private static final Strategy DAY_OF_WEEK_IN_MONTH_STRATEGY = new NumberStrategy(Calendar.DAY_OF_WEEK_IN_MONTH);
|
||||||
|
private static final Strategy HOUR_OF_DAY_STRATEGY = new NumberStrategy(Calendar.HOUR_OF_DAY);
|
||||||
|
private static final Strategy MODULO_HOUR_OF_DAY_STRATEGY = new NumberStrategy(Calendar.HOUR_OF_DAY) {
|
||||||
|
@Override
|
||||||
|
int modify(final int iValue) {
|
||||||
|
return iValue % 24;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
private static final Strategy MODULO_HOUR_STRATEGY = new NumberStrategy(Calendar.HOUR) {
|
||||||
|
@Override
|
||||||
|
int modify(final int iValue) {
|
||||||
|
return iValue % 12;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
private static final Strategy HOUR_STRATEGY = new NumberStrategy(Calendar.HOUR);
|
||||||
|
private static final Strategy MINUTE_STRATEGY = new NumberStrategy(Calendar.MINUTE);
|
||||||
|
private static final Strategy SECOND_STRATEGY = new NumberStrategy(Calendar.SECOND);
|
||||||
|
private static final Strategy MILLISECOND_STRATEGY = new NumberStrategy(Calendar.MILLISECOND);
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,265 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.telegram.android.time;
|
||||||
|
|
||||||
|
import java.text.DateFormat;
|
||||||
|
import java.text.Format;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.ConcurrentMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>FormatCache is a cache and factory for {@link Format}s.</p>
|
||||||
|
*
|
||||||
|
* @since 3.0
|
||||||
|
* @version $Id: FormatCache 892161 2009-12-18 07:21:10Z $
|
||||||
|
*/
|
||||||
|
// TODO: Before making public move from getDateTimeInstance(Integer,...) to int; or some other approach.
|
||||||
|
abstract class FormatCache<F extends Format> {
|
||||||
|
/**
|
||||||
|
* No date or no time. Used in same parameters as DateFormat.SHORT or DateFormat.LONG
|
||||||
|
*/
|
||||||
|
static final int NONE = -1;
|
||||||
|
|
||||||
|
private final ConcurrentMap<MultipartKey, F> cInstanceCache
|
||||||
|
= new ConcurrentHashMap<MultipartKey, F>(7);
|
||||||
|
|
||||||
|
private static final ConcurrentMap<MultipartKey, String> cDateTimeInstanceCache
|
||||||
|
= new ConcurrentHashMap<MultipartKey, String>(7);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Gets a formatter instance using the default pattern in the
|
||||||
|
* default timezone and locale.</p>
|
||||||
|
*
|
||||||
|
* @return a date/time formatter
|
||||||
|
*/
|
||||||
|
public F getInstance() {
|
||||||
|
return getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, TimeZone.getDefault(), Locale.getDefault());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Gets a formatter instance using the specified pattern, time zone
|
||||||
|
* and locale.</p>
|
||||||
|
*
|
||||||
|
* @param pattern {@link java.text.SimpleDateFormat} compatible
|
||||||
|
* pattern, non-null
|
||||||
|
* @param timeZone the time zone, null means use the default TimeZone
|
||||||
|
* @param locale the locale, null means use the default Locale
|
||||||
|
* @return a pattern based date/time formatter
|
||||||
|
* @throws IllegalArgumentException if pattern is invalid
|
||||||
|
* or <code>null</code>
|
||||||
|
*/
|
||||||
|
public F getInstance(final String pattern, TimeZone timeZone, Locale locale) {
|
||||||
|
if (pattern == null) {
|
||||||
|
throw new NullPointerException("pattern must not be null");
|
||||||
|
}
|
||||||
|
if (timeZone == null) {
|
||||||
|
timeZone = TimeZone.getDefault();
|
||||||
|
}
|
||||||
|
if (locale == null) {
|
||||||
|
locale = Locale.getDefault();
|
||||||
|
}
|
||||||
|
final MultipartKey key = new MultipartKey(pattern, timeZone, locale);
|
||||||
|
F format = cInstanceCache.get(key);
|
||||||
|
if (format == null) {
|
||||||
|
format = createInstance(pattern, timeZone, locale);
|
||||||
|
final F previousValue = cInstanceCache.putIfAbsent(key, format);
|
||||||
|
if (previousValue != null) {
|
||||||
|
// another thread snuck in and did the same work
|
||||||
|
// we should return the instance that is in ConcurrentMap
|
||||||
|
format = previousValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Create a format instance using the specified pattern, time zone
|
||||||
|
* and locale.</p>
|
||||||
|
*
|
||||||
|
* @param pattern {@link java.text.SimpleDateFormat} compatible pattern, this will not be null.
|
||||||
|
* @param timeZone time zone, this will not be null.
|
||||||
|
* @param locale locale, this will not be null.
|
||||||
|
* @return a pattern based date/time formatter
|
||||||
|
* @throws IllegalArgumentException if pattern is invalid
|
||||||
|
* or <code>null</code>
|
||||||
|
*/
|
||||||
|
abstract protected F createInstance(String pattern, TimeZone timeZone, Locale locale);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Gets a date/time formatter instance using the specified style,
|
||||||
|
* time zone and locale.</p>
|
||||||
|
*
|
||||||
|
* @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT, null indicates no date in format
|
||||||
|
* @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT, null indicates no time in format
|
||||||
|
* @param timeZone optional time zone, overrides time zone of
|
||||||
|
* formatted date, null means use default Locale
|
||||||
|
* @param locale optional locale, overrides system locale
|
||||||
|
* @return a localized standard date/time formatter
|
||||||
|
* @throws IllegalArgumentException if the Locale has no date/time
|
||||||
|
* pattern defined
|
||||||
|
*/
|
||||||
|
// This must remain private, see LANG-884
|
||||||
|
private F getDateTimeInstance(final Integer dateStyle, final Integer timeStyle, final TimeZone timeZone, Locale locale) {
|
||||||
|
if (locale == null) {
|
||||||
|
locale = Locale.getDefault();
|
||||||
|
}
|
||||||
|
final String pattern = getPatternForStyle(dateStyle, timeStyle, locale);
|
||||||
|
return getInstance(pattern, timeZone, locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Gets a date/time formatter instance using the specified style,
|
||||||
|
* time zone and locale.</p>
|
||||||
|
*
|
||||||
|
* @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT
|
||||||
|
* @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT
|
||||||
|
* @param timeZone optional time zone, overrides time zone of
|
||||||
|
* formatted date, null means use default Locale
|
||||||
|
* @param locale optional locale, overrides system locale
|
||||||
|
* @return a localized standard date/time formatter
|
||||||
|
* @throws IllegalArgumentException if the Locale has no date/time
|
||||||
|
* pattern defined
|
||||||
|
*/
|
||||||
|
// package protected, for access from FastDateFormat; do not make public or protected
|
||||||
|
F getDateTimeInstance(final int dateStyle, final int timeStyle, final TimeZone timeZone, Locale locale) {
|
||||||
|
return getDateTimeInstance(Integer.valueOf(dateStyle), Integer.valueOf(timeStyle), timeZone, locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Gets a date formatter instance using the specified style,
|
||||||
|
* time zone and locale.</p>
|
||||||
|
*
|
||||||
|
* @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT
|
||||||
|
* @param timeZone optional time zone, overrides time zone of
|
||||||
|
* formatted date, null means use default Locale
|
||||||
|
* @param locale optional locale, overrides system locale
|
||||||
|
* @return a localized standard date/time formatter
|
||||||
|
* @throws IllegalArgumentException if the Locale has no date/time
|
||||||
|
* pattern defined
|
||||||
|
*/
|
||||||
|
// package protected, for access from FastDateFormat; do not make public or protected
|
||||||
|
F getDateInstance(final int dateStyle, final TimeZone timeZone, Locale locale) {
|
||||||
|
return getDateTimeInstance(Integer.valueOf(dateStyle), null, timeZone, locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Gets a time formatter instance using the specified style,
|
||||||
|
* time zone and locale.</p>
|
||||||
|
*
|
||||||
|
* @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT
|
||||||
|
* @param timeZone optional time zone, overrides time zone of
|
||||||
|
* formatted date, null means use default Locale
|
||||||
|
* @param locale optional locale, overrides system locale
|
||||||
|
* @return a localized standard date/time formatter
|
||||||
|
* @throws IllegalArgumentException if the Locale has no date/time
|
||||||
|
* pattern defined
|
||||||
|
*/
|
||||||
|
// package protected, for access from FastDateFormat; do not make public or protected
|
||||||
|
F getTimeInstance(final int timeStyle, final TimeZone timeZone, Locale locale) {
|
||||||
|
return getDateTimeInstance(null, Integer.valueOf(timeStyle), timeZone, locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Gets a date/time format for the specified styles and locale.</p>
|
||||||
|
*
|
||||||
|
* @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT, null indicates no date in format
|
||||||
|
* @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT, null indicates no time in format
|
||||||
|
* @param locale The non-null locale of the desired format
|
||||||
|
* @return a localized standard date/time format
|
||||||
|
* @throws IllegalArgumentException if the Locale has no date/time pattern defined
|
||||||
|
*/
|
||||||
|
// package protected, for access from test code; do not make public or protected
|
||||||
|
static String getPatternForStyle(final Integer dateStyle, final Integer timeStyle, final Locale locale) {
|
||||||
|
final MultipartKey key = new MultipartKey(dateStyle, timeStyle, locale);
|
||||||
|
|
||||||
|
String pattern = cDateTimeInstanceCache.get(key);
|
||||||
|
if (pattern == null) {
|
||||||
|
try {
|
||||||
|
DateFormat formatter;
|
||||||
|
if (dateStyle == null) {
|
||||||
|
formatter = DateFormat.getTimeInstance(timeStyle.intValue(), locale);
|
||||||
|
} else if (timeStyle == null) {
|
||||||
|
formatter = DateFormat.getDateInstance(dateStyle.intValue(), locale);
|
||||||
|
} else {
|
||||||
|
formatter = DateFormat.getDateTimeInstance(dateStyle.intValue(), timeStyle.intValue(), locale);
|
||||||
|
}
|
||||||
|
pattern = ((SimpleDateFormat) formatter).toPattern();
|
||||||
|
final String previous = cDateTimeInstanceCache.putIfAbsent(key, pattern);
|
||||||
|
if (previous != null) {
|
||||||
|
// even though it doesn't matter if another thread put the pattern
|
||||||
|
// it's still good practice to return the String instance that is
|
||||||
|
// actually in the ConcurrentMap
|
||||||
|
pattern = previous;
|
||||||
|
}
|
||||||
|
} catch (final ClassCastException ex) {
|
||||||
|
throw new IllegalArgumentException("No date time pattern for locale: " + locale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pattern;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Helper class to hold multi-part Map keys</p>
|
||||||
|
*/
|
||||||
|
private static class MultipartKey {
|
||||||
|
private final Object[] keys;
|
||||||
|
private int hashCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an instance of <code>MultipartKey</code> to hold the specified objects.
|
||||||
|
*
|
||||||
|
* @param keys the set of objects that make up the key. Each key may be null.
|
||||||
|
*/
|
||||||
|
public MultipartKey(final Object... keys) {
|
||||||
|
this.keys = keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean equals(final Object obj) {
|
||||||
|
// Eliminate the usual boilerplate because
|
||||||
|
// this inner static class is only used in a generic ConcurrentHashMap
|
||||||
|
// which will not compare against other Object types
|
||||||
|
return Arrays.equals(keys, ((MultipartKey) obj).keys);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
if (hashCode == 0) {
|
||||||
|
int rc = 0;
|
||||||
|
for (final Object key : keys) {
|
||||||
|
if (key != null) {
|
||||||
|
rc = rc * 7 + key.hashCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hashCode = rc;
|
||||||
|
}
|
||||||
|
return hashCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -16,7 +16,7 @@ import com.coremedia.iso.boxes.AbstractMediaHeaderBox;
|
|||||||
import com.coremedia.iso.boxes.SampleDescriptionBox;
|
import com.coremedia.iso.boxes.SampleDescriptionBox;
|
||||||
import com.coremedia.iso.boxes.SoundMediaHeaderBox;
|
import com.coremedia.iso.boxes.SoundMediaHeaderBox;
|
||||||
import com.coremedia.iso.boxes.VideoMediaHeaderBox;
|
import com.coremedia.iso.boxes.VideoMediaHeaderBox;
|
||||||
import com.coremedia.iso.boxes.h264.AvcConfigurationBox;
|
import com.mp4parser.iso14496.part15.AvcConfigurationBox;
|
||||||
import com.coremedia.iso.boxes.sampleentry.AudioSampleEntry;
|
import com.coremedia.iso.boxes.sampleentry.AudioSampleEntry;
|
||||||
import com.coremedia.iso.boxes.sampleentry.VisualSampleEntry;
|
import com.coremedia.iso.boxes.sampleentry.VisualSampleEntry;
|
||||||
import com.googlecode.mp4parser.boxes.mp4.ESDescriptorBox;
|
import com.googlecode.mp4parser.boxes.mp4.ESDescriptorBox;
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* Copyright Nikolai Kudashov, 2013.
|
* Copyright Nikolai Kudashov, 2013.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.telegram.ui;
|
package org.telegram.messenger;
|
||||||
|
|
||||||
import android.app.AlarmManager;
|
import android.app.AlarmManager;
|
||||||
import android.app.Application;
|
import android.app.Application;
|
||||||
@ -21,6 +21,7 @@ import android.content.pm.PackageManager;
|
|||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.os.AsyncTask;
|
import android.os.AsyncTask;
|
||||||
|
import android.os.Build;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.PowerManager;
|
import android.os.PowerManager;
|
||||||
|
|
||||||
@ -33,15 +34,10 @@ import org.telegram.android.ContactsController;
|
|||||||
import org.telegram.android.MediaController;
|
import org.telegram.android.MediaController;
|
||||||
import org.telegram.android.NotificationsService;
|
import org.telegram.android.NotificationsService;
|
||||||
import org.telegram.android.SendMessagesHelper;
|
import org.telegram.android.SendMessagesHelper;
|
||||||
import org.telegram.messenger.BuildVars;
|
|
||||||
import org.telegram.messenger.ConnectionsManager;
|
|
||||||
import org.telegram.messenger.FileLog;
|
|
||||||
import org.telegram.android.LocaleController;
|
import org.telegram.android.LocaleController;
|
||||||
import org.telegram.android.MessagesController;
|
import org.telegram.android.MessagesController;
|
||||||
import org.telegram.android.NativeLoader;
|
import org.telegram.android.NativeLoader;
|
||||||
import org.telegram.android.ScreenReceiver;
|
import org.telegram.android.ScreenReceiver;
|
||||||
import org.telegram.messenger.UserConfig;
|
|
||||||
import org.telegram.messenger.Utilities;
|
|
||||||
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
@ -112,14 +108,17 @@ public class ApplicationLoader extends Application {
|
|||||||
@Override
|
@Override
|
||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
super.onCreate();
|
super.onCreate();
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT < 11) {
|
||||||
|
java.lang.System.setProperty("java.net.preferIPv4Stack", "true");
|
||||||
|
java.lang.System.setProperty("java.net.preferIPv6Addresses", "false");
|
||||||
|
}
|
||||||
|
|
||||||
applicationContext = getApplicationContext();
|
applicationContext = getApplicationContext();
|
||||||
NativeLoader.initNativeLibs(ApplicationLoader.applicationContext);
|
NativeLoader.initNativeLibs(ApplicationLoader.applicationContext);
|
||||||
|
|
||||||
applicationHandler = new Handler(applicationContext.getMainLooper());
|
applicationHandler = new Handler(applicationContext.getMainLooper());
|
||||||
|
|
||||||
java.lang.System.setProperty("java.net.preferIPv4Stack", "true");
|
|
||||||
java.lang.System.setProperty("java.net.preferIPv6Addresses", "false");
|
|
||||||
|
|
||||||
startPushService();
|
startPushService();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,7 +267,7 @@ public class ApplicationLoader extends Application {
|
|||||||
UserConfig.registeredForPush = !isNew;
|
UserConfig.registeredForPush = !isNew;
|
||||||
UserConfig.saveConfig(false);
|
UserConfig.saveConfig(false);
|
||||||
if (UserConfig.getClientUserId() != 0) {
|
if (UserConfig.getClientUserId() != 0) {
|
||||||
AndroidUtilities.RunOnUIThread(new Runnable() {
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
MessagesController.getInstance().registerForPush(regid);
|
MessagesController.getInstance().registerForPush(regid);
|
@ -14,7 +14,6 @@ import android.content.pm.PackageInfo;
|
|||||||
import android.net.ConnectivityManager;
|
import android.net.ConnectivityManager;
|
||||||
import android.net.NetworkInfo;
|
import android.net.NetworkInfo;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.PowerManager;
|
|
||||||
import android.util.Base64;
|
import android.util.Base64;
|
||||||
|
|
||||||
import org.telegram.android.AndroidUtilities;
|
import org.telegram.android.AndroidUtilities;
|
||||||
@ -22,7 +21,6 @@ import org.telegram.android.ContactsController;
|
|||||||
import org.telegram.android.LocaleController;
|
import org.telegram.android.LocaleController;
|
||||||
import org.telegram.android.MessagesController;
|
import org.telegram.android.MessagesController;
|
||||||
import org.telegram.android.NotificationCenter;
|
import org.telegram.android.NotificationCenter;
|
||||||
import org.telegram.ui.ApplicationLoader;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -83,8 +81,6 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection.
|
|||||||
|
|
||||||
private volatile long nextCallToken = 1;
|
private volatile long nextCallToken = 1;
|
||||||
|
|
||||||
private PowerManager.WakeLock wakeLock = null;
|
|
||||||
|
|
||||||
private static volatile ConnectionsManager Instance = null;
|
private static volatile ConnectionsManager Instance = null;
|
||||||
public static ConnectionsManager getInstance() {
|
public static ConnectionsManager getInstance() {
|
||||||
ConnectionsManager localInstance = Instance;
|
ConnectionsManager localInstance = Instance;
|
||||||
@ -217,10 +213,6 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection.
|
|||||||
}
|
}
|
||||||
|
|
||||||
Utilities.stageQueue.postRunnable(stageRunnable, 1000);
|
Utilities.stageQueue.postRunnable(stageRunnable, 1000);
|
||||||
|
|
||||||
PowerManager pm = (PowerManager)ApplicationLoader.applicationContext.getSystemService(Context.POWER_SERVICE);
|
|
||||||
wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "lock");
|
|
||||||
wakeLock.setReferenceCounted(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getConnectionState() {
|
public int getConnectionState() {
|
||||||
@ -425,7 +417,7 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection.
|
|||||||
pushSessionId = Utilities.random.nextLong();
|
pushSessionId = Utilities.random.nextLong();
|
||||||
}
|
}
|
||||||
if (currentDatacenterId == 0) {
|
if (currentDatacenterId == 0) {
|
||||||
currentDatacenterId = 1;
|
currentDatacenterId = 2;
|
||||||
}
|
}
|
||||||
saveSession();
|
saveSession();
|
||||||
}
|
}
|
||||||
@ -439,12 +431,12 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection.
|
|||||||
if (isTestBackend == 0) {
|
if (isTestBackend == 0) {
|
||||||
Datacenter datacenter = new Datacenter();
|
Datacenter datacenter = new Datacenter();
|
||||||
datacenter.datacenterId = 1;
|
datacenter.datacenterId = 1;
|
||||||
datacenter.addAddressAndPort("173.240.5.1", 443);
|
datacenter.addAddressAndPort("149.154.175.50", 443);
|
||||||
datacenters.put(datacenter.datacenterId, datacenter);
|
datacenters.put(datacenter.datacenterId, datacenter);
|
||||||
|
|
||||||
datacenter = new Datacenter();
|
datacenter = new Datacenter();
|
||||||
datacenter.datacenterId = 2;
|
datacenter.datacenterId = 2;
|
||||||
datacenter.addAddressAndPort("149.154.167.50", 443);
|
datacenter.addAddressAndPort("149.154.167.51", 443);
|
||||||
datacenters.put(datacenter.datacenterId, datacenter);
|
datacenters.put(datacenter.datacenterId, datacenter);
|
||||||
|
|
||||||
datacenter = new Datacenter();
|
datacenter = new Datacenter();
|
||||||
@ -454,7 +446,7 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection.
|
|||||||
|
|
||||||
datacenter = new Datacenter();
|
datacenter = new Datacenter();
|
||||||
datacenter.datacenterId = 4;
|
datacenter.datacenterId = 4;
|
||||||
datacenter.addAddressAndPort("149.154.167.90", 443);
|
datacenter.addAddressAndPort("149.154.167.91", 443);
|
||||||
datacenters.put(datacenter.datacenterId, datacenter);
|
datacenters.put(datacenter.datacenterId, datacenter);
|
||||||
|
|
||||||
datacenter = new Datacenter();
|
datacenter = new Datacenter();
|
||||||
@ -480,7 +472,7 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection.
|
|||||||
} else if (datacenters.size() == 1) {
|
} else if (datacenters.size() == 1) {
|
||||||
Datacenter datacenter = new Datacenter();
|
Datacenter datacenter = new Datacenter();
|
||||||
datacenter.datacenterId = 2;
|
datacenter.datacenterId = 2;
|
||||||
datacenter.addAddressAndPort("149.154.167.50", 443);
|
datacenter.addAddressAndPort("149.154.167.51", 443);
|
||||||
datacenters.put(datacenter.datacenterId, datacenter);
|
datacenters.put(datacenter.datacenterId, datacenter);
|
||||||
|
|
||||||
datacenter = new Datacenter();
|
datacenter = new Datacenter();
|
||||||
@ -490,12 +482,12 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection.
|
|||||||
|
|
||||||
datacenter = new Datacenter();
|
datacenter = new Datacenter();
|
||||||
datacenter.datacenterId = 4;
|
datacenter.datacenterId = 4;
|
||||||
datacenter.addAddressAndPort("31.210.235.12", 443);
|
datacenter.addAddressAndPort("149.154.167.91", 443);
|
||||||
datacenters.put(datacenter.datacenterId, datacenter);
|
datacenters.put(datacenter.datacenterId, datacenter);
|
||||||
|
|
||||||
datacenter = new Datacenter();
|
datacenter = new Datacenter();
|
||||||
datacenter.datacenterId = 5;
|
datacenter.datacenterId = 5;
|
||||||
datacenter.addAddressAndPort("116.51.22.2", 443);
|
datacenter.addAddressAndPort("149.154.171.5", 443);
|
||||||
datacenters.put(datacenter.datacenterId, datacenter);
|
datacenters.put(datacenter.datacenterId, datacenter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -646,7 +638,7 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection.
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void bindRequestToGuid(final Long request, final int guid) {
|
public void bindRequestToGuid(final Long request, final int guid) {
|
||||||
AndroidUtilities.RunOnUIThread(new Runnable() {
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
ArrayList<Long> requests = requestsByGuids.get(guid);
|
ArrayList<Long> requests = requestsByGuids.get(guid);
|
||||||
@ -659,7 +651,7 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection.
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void removeRequestInClass(final Long request) {
|
public void removeRequestInClass(final Long request) {
|
||||||
AndroidUtilities.RunOnUIThread(new Runnable() {
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
Integer guid = requestsByClass.get(request);
|
Integer guid = requestsByClass.get(request);
|
||||||
@ -831,12 +823,11 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection.
|
|||||||
if (invoke.system_version == null || invoke.system_version.length() == 0) {
|
if (invoke.system_version == null || invoke.system_version.length() == 0) {
|
||||||
invoke.system_version = "SDK Unknown";
|
invoke.system_version = "SDK Unknown";
|
||||||
}
|
}
|
||||||
object = invoke;
|
TLRPC.invokeWithLayer invoke2 = new TLRPC.invokeWithLayer();
|
||||||
|
invoke2.query = invoke;
|
||||||
|
FileLog.d("wrap in layer", "" + object);
|
||||||
|
object = invoke2;
|
||||||
}
|
}
|
||||||
TLRPC.invokeWithLayer18 invoke = new TLRPC.invokeWithLayer18();
|
|
||||||
invoke.query = object;
|
|
||||||
FileLog.d("wrap in layer", "" + object);
|
|
||||||
return invoke;
|
|
||||||
}
|
}
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
@ -1121,13 +1112,13 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection.
|
|||||||
|
|
||||||
request.retryCount++;
|
request.retryCount++;
|
||||||
|
|
||||||
if ((request.flags & RPCRequest.RPCRequestClassDownloadMedia) != 0) {
|
if (!request.salt && (request.flags & RPCRequest.RPCRequestClassDownloadMedia) != 0) {
|
||||||
int retryMax = 10;
|
int retryMax = 10;
|
||||||
if ((request.flags & RPCRequest.RPCRequestClassForceDownload) == 0) {
|
if ((request.flags & RPCRequest.RPCRequestClassForceDownload) == 0) {
|
||||||
if (request.wait) {
|
if (request.wait) {
|
||||||
retryMax = 1;
|
retryMax = 1;
|
||||||
} else {
|
} else {
|
||||||
retryMax = 3;
|
retryMax = 6;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (request.retryCount >= retryMax) {
|
if (request.retryCount >= retryMax) {
|
||||||
@ -1614,12 +1605,12 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection.
|
|||||||
TLRPC.TL_protoMessage message = networkMessage.protoMessage;
|
TLRPC.TL_protoMessage message = networkMessage.protoMessage;
|
||||||
|
|
||||||
if (BuildVars.DEBUG_VERSION) {
|
if (BuildVars.DEBUG_VERSION) {
|
||||||
if (message.body instanceof TLRPC.invokeWithLayer18) {
|
if (message.body instanceof TLRPC.invokeWithLayer) {
|
||||||
FileLog.d("tmessages", connection.getSissionId() + ":DC" + datacenter.datacenterId + "> Send message (" + message.seqno + ", " + message.msg_id + "): " + ((TLRPC.invokeWithLayer18)message.body).query);
|
FileLog.d("tmessages", connection.getSissionId() + ":DC" + datacenter.datacenterId + "> Send message (" + message.seqno + ", " + message.msg_id + "): " + ((TLRPC.invokeWithLayer)message.body).query);
|
||||||
} else if (message.body instanceof TLRPC.initConnection) {
|
} else if (message.body instanceof TLRPC.initConnection) {
|
||||||
TLRPC.initConnection r = (TLRPC.initConnection)message.body;
|
TLRPC.initConnection r = (TLRPC.initConnection)message.body;
|
||||||
if (r.query instanceof TLRPC.invokeWithLayer18) {
|
if (r.query instanceof TLRPC.invokeWithLayer) {
|
||||||
FileLog.d("tmessages", connection.getSissionId() + ":DC" + datacenter.datacenterId + "> Send message (" + message.seqno + ", " + message.msg_id + "): " + ((TLRPC.invokeWithLayer18)r.query).query);
|
FileLog.d("tmessages", connection.getSissionId() + ":DC" + datacenter.datacenterId + "> Send message (" + message.seqno + ", " + message.msg_id + "): " + ((TLRPC.invokeWithLayer)r.query).query);
|
||||||
} else {
|
} else {
|
||||||
FileLog.d("tmessages", connection.getSissionId() + ":DC" + datacenter.datacenterId + "> Send message (" + message.seqno + ", " + message.msg_id + "): " + r.query);
|
FileLog.d("tmessages", connection.getSissionId() + ":DC" + datacenter.datacenterId + "> Send message (" + message.seqno + ", " + message.msg_id + "): " + r.query);
|
||||||
}
|
}
|
||||||
@ -1654,12 +1645,12 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection.
|
|||||||
TLRPC.TL_protoMessage message = networkMessage.protoMessage;
|
TLRPC.TL_protoMessage message = networkMessage.protoMessage;
|
||||||
containerMessages.add(message);
|
containerMessages.add(message);
|
||||||
if (BuildVars.DEBUG_VERSION) {
|
if (BuildVars.DEBUG_VERSION) {
|
||||||
if (message.body instanceof TLRPC.invokeWithLayer18) {
|
if (message.body instanceof TLRPC.invokeWithLayer) {
|
||||||
FileLog.d("tmessages", connection.getSissionId() + ":DC" + datacenter.datacenterId + "> Send message (" + message.seqno + ", " + message.msg_id + "): " + ((TLRPC.invokeWithLayer18)message.body).query);
|
FileLog.d("tmessages", connection.getSissionId() + ":DC" + datacenter.datacenterId + "> Send message (" + message.seqno + ", " + message.msg_id + "): " + ((TLRPC.invokeWithLayer)message.body).query);
|
||||||
} else if (message.body instanceof TLRPC.initConnection) {
|
} else if (message.body instanceof TLRPC.initConnection) {
|
||||||
TLRPC.initConnection r = (TLRPC.initConnection)message.body;
|
TLRPC.initConnection r = (TLRPC.initConnection)message.body;
|
||||||
if (r.query instanceof TLRPC.invokeWithLayer18) {
|
if (r.query instanceof TLRPC.invokeWithLayer) {
|
||||||
FileLog.d("tmessages", connection.getSissionId() + ":DC" + datacenter.datacenterId + "> Send message (" + message.seqno + ", " + message.msg_id + "): " + ((TLRPC.invokeWithLayer18)r.query).query);
|
FileLog.d("tmessages", connection.getSissionId() + ":DC" + datacenter.datacenterId + "> Send message (" + message.seqno + ", " + message.msg_id + "): " + ((TLRPC.invokeWithLayer)r.query).query);
|
||||||
} else {
|
} else {
|
||||||
FileLog.d("tmessages", connection.getSissionId() + ":DC" + datacenter.datacenterId + "> Send message (" + message.seqno + ", " + message.msg_id + "): " + r.query);
|
FileLog.d("tmessages", connection.getSissionId() + ":DC" + datacenter.datacenterId + "> Send message (" + message.seqno + ", " + message.msg_id + "): " + r.query);
|
||||||
}
|
}
|
||||||
@ -2139,14 +2130,6 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection.
|
|||||||
} else {
|
} else {
|
||||||
if (resultContainer.result instanceof TLRPC.updates_Difference) {
|
if (resultContainer.result instanceof TLRPC.updates_Difference) {
|
||||||
pushMessagesReceived = true;
|
pushMessagesReceived = true;
|
||||||
AndroidUtilities.RunOnUIThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
if (wakeLock.isHeld()) {
|
|
||||||
wakeLock.release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
request.completionBlock.run(resultContainer.result, null);
|
request.completionBlock.run(resultContainer.result, null);
|
||||||
}
|
}
|
||||||
@ -2158,7 +2141,7 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection.
|
|||||||
if ((request.flags & RPCRequest.RPCRequestClassGeneric) != 0) {
|
if ((request.flags & RPCRequest.RPCRequestClassGeneric) != 0) {
|
||||||
if (UserConfig.isClientActivated()) {
|
if (UserConfig.isClientActivated()) {
|
||||||
UserConfig.clearConfig();
|
UserConfig.clearConfig();
|
||||||
AndroidUtilities.RunOnUIThread(new Runnable() {
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
NotificationCenter.getInstance().postNotificationName(NotificationCenter.appDidLogout);
|
NotificationCenter.getInstance().postNotificationName(NotificationCenter.appDidLogout);
|
||||||
@ -2252,6 +2235,19 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection.
|
|||||||
|
|
||||||
lastOutgoingMessageId = Math.max(messageId, lastOutgoingMessageId);
|
lastOutgoingMessageId = Math.max(messageId, lastOutgoingMessageId);
|
||||||
}
|
}
|
||||||
|
long resultMid = ((TLRPC.TL_bad_server_salt) message).bad_msg_id;
|
||||||
|
if (resultMid != 0) {
|
||||||
|
for (RPCRequest request : runningRequests) {
|
||||||
|
if ((request.flags & RPCRequest.RPCRequestClassDownloadMedia) == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (request.respondsToMessageId(resultMid)) {
|
||||||
|
request.retryCount = 0;
|
||||||
|
request.salt = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
datacenter.clearServerSalts();
|
datacenter.clearServerSalts();
|
||||||
|
|
||||||
@ -2317,23 +2313,9 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection.
|
|||||||
if (paused) {
|
if (paused) {
|
||||||
pushMessagesReceived = false;
|
pushMessagesReceived = false;
|
||||||
}
|
}
|
||||||
AndroidUtilities.RunOnUIThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
wakeLock.acquire(20000);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
resumeNetworkInternal();
|
resumeNetworkInternal();
|
||||||
} else {
|
} else {
|
||||||
pushMessagesReceived = true;
|
pushMessagesReceived = true;
|
||||||
AndroidUtilities.RunOnUIThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
if (wakeLock.isHeld()) {
|
|
||||||
wakeLock.release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
MessagesController.getInstance().processUpdates((TLRPC.Updates) message, false);
|
MessagesController.getInstance().processUpdates((TLRPC.Updates) message, false);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -2431,7 +2413,7 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection.
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
final int stateCopy = connectionState;
|
final int stateCopy = connectionState;
|
||||||
AndroidUtilities.RunOnUIThread(new Runnable() {
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
NotificationCenter.getInstance().postNotificationName(NotificationCenter.didUpdatedConnectionState, stateCopy);
|
NotificationCenter.getInstance().postNotificationName(NotificationCenter.didUpdatedConnectionState, stateCopy);
|
||||||
@ -2481,7 +2463,7 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection.
|
|||||||
if (ConnectionsManager.getInstance().connectionState == 3 && !MessagesController.getInstance().gettingDifference && !MessagesController.getInstance().gettingDifferenceAgain) {
|
if (ConnectionsManager.getInstance().connectionState == 3 && !MessagesController.getInstance().gettingDifference && !MessagesController.getInstance().gettingDifferenceAgain) {
|
||||||
ConnectionsManager.getInstance().connectionState = 0;
|
ConnectionsManager.getInstance().connectionState = 0;
|
||||||
final int stateCopy = ConnectionsManager.getInstance().connectionState;
|
final int stateCopy = ConnectionsManager.getInstance().connectionState;
|
||||||
AndroidUtilities.RunOnUIThread(new Runnable() {
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
NotificationCenter.getInstance().postNotificationName(NotificationCenter.didUpdatedConnectionState, stateCopy);
|
NotificationCenter.getInstance().postNotificationName(NotificationCenter.didUpdatedConnectionState, stateCopy);
|
||||||
@ -2497,7 +2479,7 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection.
|
|||||||
if (connectionState == 1 || connectionState == 2) {
|
if (connectionState == 1 || connectionState == 2) {
|
||||||
connectionState = 3;
|
connectionState = 3;
|
||||||
final int stateCopy = connectionState;
|
final int stateCopy = connectionState;
|
||||||
AndroidUtilities.RunOnUIThread(new Runnable() {
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
NotificationCenter.getInstance().postNotificationName(NotificationCenter.didUpdatedConnectionState, stateCopy);
|
NotificationCenter.getInstance().postNotificationName(NotificationCenter.didUpdatedConnectionState, stateCopy);
|
||||||
@ -2587,7 +2569,7 @@ public class ConnectionsManager implements Action.ActionDelegate, TcpConnection.
|
|||||||
if (message == null) {
|
if (message == null) {
|
||||||
FileLog.e("tmessages", "***** Error parsing message: " + constructor);
|
FileLog.e("tmessages", "***** Error parsing message: " + constructor);
|
||||||
} else {
|
} else {
|
||||||
FileLog.e("tmessages", "received object " + message);
|
FileLog.d("tmessages", "received object " + message);
|
||||||
processMessage(message, messageId, messageSeqNo, messageServerSalt, connection, 0, 0);
|
processMessage(message, messageId, messageSeqNo, messageServerSalt, connection, 0, 0);
|
||||||
connection.addProcessedMessageId(messageId);
|
connection.addProcessedMessageId(messageId);
|
||||||
|
|
||||||
|
@ -11,8 +11,6 @@ package org.telegram.messenger;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
|
|
||||||
import org.telegram.ui.ApplicationLoader;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
@ -11,8 +11,7 @@ package org.telegram.messenger;
|
|||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import org.telegram.android.FastDateFormat;
|
import org.telegram.android.time.FastDateFormat;
|
||||||
import org.telegram.ui.ApplicationLoader;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
|
@ -11,8 +11,6 @@ package org.telegram.messenger;
|
|||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
|
|
||||||
import org.telegram.ui.ApplicationLoader;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
|
@ -37,6 +37,7 @@ public class RPCRequest {
|
|||||||
int serverFailureCount;
|
int serverFailureCount;
|
||||||
int flags;
|
int flags;
|
||||||
boolean wait = false;
|
boolean wait = false;
|
||||||
|
boolean salt = false;
|
||||||
protected int retryCount = 0;
|
protected int retryCount = 0;
|
||||||
protected int lastResendTime = 0;
|
protected int lastResendTime = 0;
|
||||||
protected boolean completed = false;
|
protected boolean completed = false;
|
||||||
|
@ -51,6 +51,8 @@ public class TLClassStore {
|
|||||||
classStore.put(TLRPC.TL_updates_difference.constructor, TLRPC.TL_updates_difference.class);
|
classStore.put(TLRPC.TL_updates_difference.constructor, TLRPC.TL_updates_difference.class);
|
||||||
classStore.put(TLRPC.TL_geoPointEmpty.constructor, TLRPC.TL_geoPointEmpty.class);
|
classStore.put(TLRPC.TL_geoPointEmpty.constructor, TLRPC.TL_geoPointEmpty.class);
|
||||||
classStore.put(TLRPC.TL_geoPoint.constructor, TLRPC.TL_geoPoint.class);
|
classStore.put(TLRPC.TL_geoPoint.constructor, TLRPC.TL_geoPoint.class);
|
||||||
|
classStore.put(TLRPC.TL_privacyKeyStatusTimestamp.constructor, TLRPC.TL_privacyKeyStatusTimestamp.class);
|
||||||
|
classStore.put(TLRPC.TL_account_privacyRules.constructor, TLRPC.TL_account_privacyRules.class);
|
||||||
classStore.put(TLRPC.TL_help_appUpdate.constructor, TLRPC.TL_help_appUpdate.class);
|
classStore.put(TLRPC.TL_help_appUpdate.constructor, TLRPC.TL_help_appUpdate.class);
|
||||||
classStore.put(TLRPC.TL_help_noAppUpdate.constructor, TLRPC.TL_help_noAppUpdate.class);
|
classStore.put(TLRPC.TL_help_noAppUpdate.constructor, TLRPC.TL_help_noAppUpdate.class);
|
||||||
classStore.put(TLRPC.TL_messageForwarded.constructor, TLRPC.TL_messageForwarded.class);
|
classStore.put(TLRPC.TL_messageForwarded.constructor, TLRPC.TL_messageForwarded.class);
|
||||||
@ -93,8 +95,15 @@ public class TLClassStore {
|
|||||||
classStore.put(TLRPC.TL_audioEmpty.constructor, TLRPC.TL_audioEmpty.class);
|
classStore.put(TLRPC.TL_audioEmpty.constructor, TLRPC.TL_audioEmpty.class);
|
||||||
classStore.put(TLRPC.TL_audio.constructor, TLRPC.TL_audio.class);
|
classStore.put(TLRPC.TL_audio.constructor, TLRPC.TL_audio.class);
|
||||||
classStore.put(TLRPC.TL_destroy_sessions_res.constructor, TLRPC.TL_destroy_sessions_res.class);
|
classStore.put(TLRPC.TL_destroy_sessions_res.constructor, TLRPC.TL_destroy_sessions_res.class);
|
||||||
|
classStore.put(TLRPC.TL_privacyValueAllowUsers.constructor, TLRPC.TL_privacyValueAllowUsers.class);
|
||||||
|
classStore.put(TLRPC.TL_privacyValueDisallowAll.constructor, TLRPC.TL_privacyValueDisallowAll.class);
|
||||||
|
classStore.put(TLRPC.TL_privacyValueAllowContacts.constructor, TLRPC.TL_privacyValueAllowContacts.class);
|
||||||
|
classStore.put(TLRPC.TL_privacyValueDisallowContacts.constructor, TLRPC.TL_privacyValueDisallowContacts.class);
|
||||||
|
classStore.put(TLRPC.TL_privacyValueAllowAll.constructor, TLRPC.TL_privacyValueAllowAll.class);
|
||||||
|
classStore.put(TLRPC.TL_privacyValueDisallowUsers.constructor, TLRPC.TL_privacyValueDisallowUsers.class);
|
||||||
classStore.put(TLRPC.TL_contacts_contacts.constructor, TLRPC.TL_contacts_contacts.class);
|
classStore.put(TLRPC.TL_contacts_contacts.constructor, TLRPC.TL_contacts_contacts.class);
|
||||||
classStore.put(TLRPC.TL_contacts_contactsNotModified.constructor, TLRPC.TL_contacts_contactsNotModified.class);
|
classStore.put(TLRPC.TL_contacts_contactsNotModified.constructor, TLRPC.TL_contacts_contactsNotModified.class);
|
||||||
|
classStore.put(TLRPC.TL_inputPrivacyKeyStatusTimestamp.constructor, TLRPC.TL_inputPrivacyKeyStatusTimestamp.class);
|
||||||
classStore.put(TLRPC.TL_photos_photos.constructor, TLRPC.TL_photos_photos.class);
|
classStore.put(TLRPC.TL_photos_photos.constructor, TLRPC.TL_photos_photos.class);
|
||||||
classStore.put(TLRPC.TL_photos_photosSlice.constructor, TLRPC.TL_photos_photosSlice.class);
|
classStore.put(TLRPC.TL_photos_photosSlice.constructor, TLRPC.TL_photos_photosSlice.class);
|
||||||
classStore.put(TLRPC.TL_chatFull.constructor, TLRPC.TL_chatFull.class);
|
classStore.put(TLRPC.TL_chatFull.constructor, TLRPC.TL_chatFull.class);
|
||||||
@ -165,6 +174,12 @@ public class TLClassStore {
|
|||||||
classStore.put(TLRPC.TL_messages_affectedHistory.constructor, TLRPC.TL_messages_affectedHistory.class);
|
classStore.put(TLRPC.TL_messages_affectedHistory.constructor, TLRPC.TL_messages_affectedHistory.class);
|
||||||
classStore.put(TLRPC.TL_documentEmpty.constructor, TLRPC.TL_documentEmpty.class);
|
classStore.put(TLRPC.TL_documentEmpty.constructor, TLRPC.TL_documentEmpty.class);
|
||||||
classStore.put(TLRPC.TL_document.constructor, TLRPC.TL_document.class);
|
classStore.put(TLRPC.TL_document.constructor, TLRPC.TL_document.class);
|
||||||
|
classStore.put(TLRPC.TL_inputPrivacyValueDisallowUsers.constructor, TLRPC.TL_inputPrivacyValueDisallowUsers.class);
|
||||||
|
classStore.put(TLRPC.TL_inputPrivacyValueDisallowAll.constructor, TLRPC.TL_inputPrivacyValueDisallowAll.class);
|
||||||
|
classStore.put(TLRPC.TL_inputPrivacyValueDisallowContacts.constructor, TLRPC.TL_inputPrivacyValueDisallowContacts.class);
|
||||||
|
classStore.put(TLRPC.TL_inputPrivacyValueAllowAll.constructor, TLRPC.TL_inputPrivacyValueAllowAll.class);
|
||||||
|
classStore.put(TLRPC.TL_inputPrivacyValueAllowContacts.constructor, TLRPC.TL_inputPrivacyValueAllowContacts.class);
|
||||||
|
classStore.put(TLRPC.TL_inputPrivacyValueAllowUsers.constructor, TLRPC.TL_inputPrivacyValueAllowUsers.class);
|
||||||
classStore.put(TLRPC.TL_inputMediaContact.constructor, TLRPC.TL_inputMediaContact.class);
|
classStore.put(TLRPC.TL_inputMediaContact.constructor, TLRPC.TL_inputMediaContact.class);
|
||||||
classStore.put(TLRPC.TL_inputMediaUploadedThumbDocument.constructor, TLRPC.TL_inputMediaUploadedThumbDocument.class);
|
classStore.put(TLRPC.TL_inputMediaUploadedThumbDocument.constructor, TLRPC.TL_inputMediaUploadedThumbDocument.class);
|
||||||
classStore.put(TLRPC.TL_inputMediaAudio.constructor, TLRPC.TL_inputMediaAudio.class);
|
classStore.put(TLRPC.TL_inputMediaAudio.constructor, TLRPC.TL_inputMediaAudio.class);
|
||||||
@ -187,9 +202,12 @@ public class TLClassStore {
|
|||||||
classStore.put(TLRPC.TL_contactSuggested.constructor, TLRPC.TL_contactSuggested.class);
|
classStore.put(TLRPC.TL_contactSuggested.constructor, TLRPC.TL_contactSuggested.class);
|
||||||
classStore.put(TLRPC.TL_server_DH_params_fail.constructor, TLRPC.TL_server_DH_params_fail.class);
|
classStore.put(TLRPC.TL_server_DH_params_fail.constructor, TLRPC.TL_server_DH_params_fail.class);
|
||||||
classStore.put(TLRPC.TL_server_DH_params_ok.constructor, TLRPC.TL_server_DH_params_ok.class);
|
classStore.put(TLRPC.TL_server_DH_params_ok.constructor, TLRPC.TL_server_DH_params_ok.class);
|
||||||
classStore.put(TLRPC.TL_userStatusEmpty.constructor, TLRPC.TL_userStatusEmpty.class);
|
|
||||||
classStore.put(TLRPC.TL_userStatusOnline.constructor, TLRPC.TL_userStatusOnline.class);
|
|
||||||
classStore.put(TLRPC.TL_userStatusOffline.constructor, TLRPC.TL_userStatusOffline.class);
|
classStore.put(TLRPC.TL_userStatusOffline.constructor, TLRPC.TL_userStatusOffline.class);
|
||||||
|
classStore.put(TLRPC.TL_userStatusLastWeek.constructor, TLRPC.TL_userStatusLastWeek.class);
|
||||||
|
classStore.put(TLRPC.TL_userStatusEmpty.constructor, TLRPC.TL_userStatusEmpty.class);
|
||||||
|
classStore.put(TLRPC.TL_userStatusLastMonth.constructor, TLRPC.TL_userStatusLastMonth.class);
|
||||||
|
classStore.put(TLRPC.TL_userStatusOnline.constructor, TLRPC.TL_userStatusOnline.class);
|
||||||
|
classStore.put(TLRPC.TL_userStatusRecently.constructor, TLRPC.TL_userStatusRecently.class);
|
||||||
classStore.put(TLRPC.TL_msg_copy.constructor, TLRPC.TL_msg_copy.class);
|
classStore.put(TLRPC.TL_msg_copy.constructor, TLRPC.TL_msg_copy.class);
|
||||||
classStore.put(TLRPC.TL_contacts_importedContacts.constructor, TLRPC.TL_contacts_importedContacts.class);
|
classStore.put(TLRPC.TL_contacts_importedContacts.constructor, TLRPC.TL_contacts_importedContacts.class);
|
||||||
classStore.put(TLRPC.TL_futureSalt.constructor, TLRPC.TL_futureSalt.class);
|
classStore.put(TLRPC.TL_futureSalt.constructor, TLRPC.TL_futureSalt.class);
|
||||||
@ -210,6 +228,7 @@ public class TLClassStore {
|
|||||||
classStore.put(TLRPC.TL_updateEncryptedChatTyping.constructor, TLRPC.TL_updateEncryptedChatTyping.class);
|
classStore.put(TLRPC.TL_updateEncryptedChatTyping.constructor, TLRPC.TL_updateEncryptedChatTyping.class);
|
||||||
classStore.put(TLRPC.TL_updateDcOptions.constructor, TLRPC.TL_updateDcOptions.class);
|
classStore.put(TLRPC.TL_updateDcOptions.constructor, TLRPC.TL_updateDcOptions.class);
|
||||||
classStore.put(TLRPC.TL_updateChatParticipants.constructor, TLRPC.TL_updateChatParticipants.class);
|
classStore.put(TLRPC.TL_updateChatParticipants.constructor, TLRPC.TL_updateChatParticipants.class);
|
||||||
|
classStore.put(TLRPC.TL_updatePrivacy.constructor, TLRPC.TL_updatePrivacy.class);
|
||||||
classStore.put(TLRPC.TL_updateEncryption.constructor, TLRPC.TL_updateEncryption.class);
|
classStore.put(TLRPC.TL_updateEncryption.constructor, TLRPC.TL_updateEncryption.class);
|
||||||
classStore.put(TLRPC.TL_updateUserBlocked.constructor, TLRPC.TL_updateUserBlocked.class);
|
classStore.put(TLRPC.TL_updateUserBlocked.constructor, TLRPC.TL_updateUserBlocked.class);
|
||||||
classStore.put(TLRPC.TL_updateActivation.constructor, TLRPC.TL_updateActivation.class);
|
classStore.put(TLRPC.TL_updateActivation.constructor, TLRPC.TL_updateActivation.class);
|
||||||
@ -328,6 +347,7 @@ public class TLClassStore {
|
|||||||
classStore.put(TLRPC.TL_inputPhotoEmpty.constructor, TLRPC.TL_inputPhotoEmpty.class);
|
classStore.put(TLRPC.TL_inputPhotoEmpty.constructor, TLRPC.TL_inputPhotoEmpty.class);
|
||||||
classStore.put(TLRPC.TL_inputPhoto.constructor, TLRPC.TL_inputPhoto.class);
|
classStore.put(TLRPC.TL_inputPhoto.constructor, TLRPC.TL_inputPhoto.class);
|
||||||
classStore.put(TLRPC.TL_importedContact.constructor, TLRPC.TL_importedContact.class);
|
classStore.put(TLRPC.TL_importedContact.constructor, TLRPC.TL_importedContact.class);
|
||||||
|
classStore.put(TLRPC.TL_accountDaysTTL.constructor, TLRPC.TL_accountDaysTTL.class);
|
||||||
classStore.put(TLRPC.TL_inputPeerContact.constructor, TLRPC.TL_inputPeerContact.class);
|
classStore.put(TLRPC.TL_inputPeerContact.constructor, TLRPC.TL_inputPeerContact.class);
|
||||||
classStore.put(TLRPC.TL_inputPeerChat.constructor, TLRPC.TL_inputPeerChat.class);
|
classStore.put(TLRPC.TL_inputPeerChat.constructor, TLRPC.TL_inputPeerChat.class);
|
||||||
classStore.put(TLRPC.TL_inputPeerEmpty.constructor, TLRPC.TL_inputPeerEmpty.class);
|
classStore.put(TLRPC.TL_inputPeerEmpty.constructor, TLRPC.TL_inputPeerEmpty.class);
|
||||||
@ -339,6 +359,13 @@ public class TLClassStore {
|
|||||||
classStore.put(TLRPC.TL_inputPhotoCrop.constructor, TLRPC.TL_inputPhotoCrop.class);
|
classStore.put(TLRPC.TL_inputPhotoCrop.constructor, TLRPC.TL_inputPhotoCrop.class);
|
||||||
classStore.put(TLRPC.TL_messages_dialogs.constructor, TLRPC.TL_messages_dialogs.class);
|
classStore.put(TLRPC.TL_messages_dialogs.constructor, TLRPC.TL_messages_dialogs.class);
|
||||||
classStore.put(TLRPC.TL_messages_dialogsSlice.constructor, TLRPC.TL_messages_dialogsSlice.class);
|
classStore.put(TLRPC.TL_messages_dialogsSlice.constructor, TLRPC.TL_messages_dialogsSlice.class);
|
||||||
|
classStore.put(TLRPC.TL_account_sentChangePhoneCode.constructor, TLRPC.TL_account_sentChangePhoneCode.class);
|
||||||
|
classStore.put(TLRPC.TL_updateUserPhone.constructor, TLRPC.TL_updateUserPhone.class);
|
||||||
|
classStore.put(TLRPC.TL_decryptedMessageActionRequestKey.constructor, TLRPC.TL_decryptedMessageActionRequestKey.class);
|
||||||
|
classStore.put(TLRPC.TL_decryptedMessageActionAcceptKey.constructor, TLRPC.TL_decryptedMessageActionAcceptKey.class);
|
||||||
|
classStore.put(TLRPC.TL_decryptedMessageActionCommitKey.constructor, TLRPC.TL_decryptedMessageActionCommitKey.class);
|
||||||
|
classStore.put(TLRPC.TL_decryptedMessageActionAbortKey.constructor, TLRPC.TL_decryptedMessageActionAbortKey.class);
|
||||||
|
classStore.put(TLRPC.TL_decryptedMessageActionNoop.constructor, TLRPC.TL_decryptedMessageActionNoop.class);
|
||||||
|
|
||||||
classStore.put(TLRPC.TL_msg_container.constructor, TLRPC.TL_msg_container.class);
|
classStore.put(TLRPC.TL_msg_container.constructor, TLRPC.TL_msg_container.class);
|
||||||
classStore.put(TLRPC.TL_fileEncryptedLocation.constructor, TLRPC.TL_fileEncryptedLocation.class);
|
classStore.put(TLRPC.TL_fileEncryptedLocation.constructor, TLRPC.TL_fileEncryptedLocation.class);
|
||||||
@ -371,6 +398,7 @@ public class TLClassStore {
|
|||||||
classStore.put(TLRPC.TL_userForeign_old.constructor, TLRPC.TL_userForeign_old.class);
|
classStore.put(TLRPC.TL_userForeign_old.constructor, TLRPC.TL_userForeign_old.class);
|
||||||
classStore.put(TLRPC.TL_userDeleted_old.constructor, TLRPC.TL_userDeleted_old.class);
|
classStore.put(TLRPC.TL_userDeleted_old.constructor, TLRPC.TL_userDeleted_old.class);
|
||||||
classStore.put(TLRPC.TL_messageEncryptedAction.constructor, TLRPC.TL_messageEncryptedAction.class);
|
classStore.put(TLRPC.TL_messageEncryptedAction.constructor, TLRPC.TL_messageEncryptedAction.class);
|
||||||
|
classStore.put(TLRPC.TL_decryptedMessageHolder.constructor, TLRPC.TL_decryptedMessageHolder.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
static TLClassStore store = null;
|
static TLClassStore store = null;
|
||||||
|
@ -272,20 +272,20 @@ public class TLRPC {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static class TL_contactStatus extends TLObject {
|
public static class TL_contactStatus extends TLObject {
|
||||||
public static int constructor = 0xaa77b873;
|
public static int constructor = 0xd3680c61;
|
||||||
|
|
||||||
public int user_id;
|
public int user_id;
|
||||||
public int expires;
|
public UserStatus status;
|
||||||
|
|
||||||
public void readParams(AbsSerializedData stream) {
|
public void readParams(AbsSerializedData stream) {
|
||||||
user_id = stream.readInt32();
|
user_id = stream.readInt32();
|
||||||
expires = stream.readInt32();
|
status = (UserStatus)TLClassStore.Instance().TLdeserialize(stream, stream.readInt32());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void serializeToStream(AbsSerializedData stream) {
|
public void serializeToStream(AbsSerializedData stream) {
|
||||||
stream.writeInt32(constructor);
|
stream.writeInt32(constructor);
|
||||||
stream.writeInt32(user_id);
|
stream.writeInt32(user_id);
|
||||||
stream.writeInt32(expires);
|
status.serializeToStream(stream);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -769,6 +769,51 @@ public class TLRPC {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class TL_privacyKeyStatusTimestamp extends TLObject {
|
||||||
|
public static int constructor = 0xbc2eab30;
|
||||||
|
|
||||||
|
|
||||||
|
public void serializeToStream(AbsSerializedData stream) {
|
||||||
|
stream.writeInt32(constructor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TL_account_privacyRules extends TLObject {
|
||||||
|
public static int constructor = 0x554abb6f;
|
||||||
|
|
||||||
|
public ArrayList<PrivacyRule> rules = new ArrayList<PrivacyRule>();
|
||||||
|
public ArrayList<User> users = new ArrayList<User>();
|
||||||
|
|
||||||
|
public void readParams(AbsSerializedData stream) {
|
||||||
|
stream.readInt32();
|
||||||
|
int count = stream.readInt32();
|
||||||
|
for (int a = 0; a < count; a++) {
|
||||||
|
rules.add((PrivacyRule)TLClassStore.Instance().TLdeserialize(stream, stream.readInt32()));
|
||||||
|
}
|
||||||
|
stream.readInt32();
|
||||||
|
count = stream.readInt32();
|
||||||
|
for (int a = 0; a < count; a++) {
|
||||||
|
users.add((User)TLClassStore.Instance().TLdeserialize(stream, stream.readInt32()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void serializeToStream(AbsSerializedData stream) {
|
||||||
|
stream.writeInt32(constructor);
|
||||||
|
stream.writeInt32(0x1cb5c415);
|
||||||
|
int count = rules.size();
|
||||||
|
stream.writeInt32(count);
|
||||||
|
for (int a = 0; a < count; a++) {
|
||||||
|
rules.get(a).serializeToStream(stream);
|
||||||
|
}
|
||||||
|
stream.writeInt32(0x1cb5c415);
|
||||||
|
count = users.size();
|
||||||
|
stream.writeInt32(count);
|
||||||
|
for (int a = 0; a < count; a++) {
|
||||||
|
users.get(a).serializeToStream(stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static class help_AppUpdate extends TLObject {
|
public static class help_AppUpdate extends TLObject {
|
||||||
public int id;
|
public int id;
|
||||||
public boolean critical;
|
public boolean critical;
|
||||||
@ -1434,6 +1479,92 @@ public class TLRPC {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class PrivacyRule extends TLObject {
|
||||||
|
public ArrayList<Integer> users = new ArrayList<Integer>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TL_privacyValueAllowUsers extends PrivacyRule {
|
||||||
|
public static int constructor = 0x4d5bbe0c;
|
||||||
|
|
||||||
|
|
||||||
|
public void readParams(AbsSerializedData stream) {
|
||||||
|
stream.readInt32();
|
||||||
|
int count = stream.readInt32();
|
||||||
|
for (int a = 0; a < count; a++) {
|
||||||
|
users.add(stream.readInt32());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void serializeToStream(AbsSerializedData stream) {
|
||||||
|
stream.writeInt32(constructor);
|
||||||
|
stream.writeInt32(0x1cb5c415);
|
||||||
|
int count = users.size();
|
||||||
|
stream.writeInt32(count);
|
||||||
|
for (Integer user : users) {
|
||||||
|
stream.writeInt32(user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TL_privacyValueDisallowAll extends PrivacyRule {
|
||||||
|
public static int constructor = 0x8b73e763;
|
||||||
|
|
||||||
|
|
||||||
|
public void serializeToStream(AbsSerializedData stream) {
|
||||||
|
stream.writeInt32(constructor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TL_privacyValueAllowContacts extends PrivacyRule {
|
||||||
|
public static int constructor = 0xfffe1bac;
|
||||||
|
|
||||||
|
|
||||||
|
public void serializeToStream(AbsSerializedData stream) {
|
||||||
|
stream.writeInt32(constructor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TL_privacyValueDisallowContacts extends PrivacyRule {
|
||||||
|
public static int constructor = 0xf888fa1a;
|
||||||
|
|
||||||
|
|
||||||
|
public void serializeToStream(AbsSerializedData stream) {
|
||||||
|
stream.writeInt32(constructor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TL_privacyValueAllowAll extends PrivacyRule {
|
||||||
|
public static int constructor = 0x65427b82;
|
||||||
|
|
||||||
|
|
||||||
|
public void serializeToStream(AbsSerializedData stream) {
|
||||||
|
stream.writeInt32(constructor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TL_privacyValueDisallowUsers extends PrivacyRule {
|
||||||
|
public static int constructor = 0xc7f49b7;
|
||||||
|
|
||||||
|
|
||||||
|
public void readParams(AbsSerializedData stream) {
|
||||||
|
stream.readInt32();
|
||||||
|
int count = stream.readInt32();
|
||||||
|
for (int a = 0; a < count; a++) {
|
||||||
|
users.add(stream.readInt32());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void serializeToStream(AbsSerializedData stream) {
|
||||||
|
stream.writeInt32(constructor);
|
||||||
|
stream.writeInt32(0x1cb5c415);
|
||||||
|
int count = users.size();
|
||||||
|
stream.writeInt32(count);
|
||||||
|
for (Integer user : users) {
|
||||||
|
stream.writeInt32(user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static class contacts_Contacts extends TLObject {
|
public static class contacts_Contacts extends TLObject {
|
||||||
public ArrayList<TL_contact> contacts = new ArrayList<TL_contact>();
|
public ArrayList<TL_contact> contacts = new ArrayList<TL_contact>();
|
||||||
public ArrayList<User> users = new ArrayList<User>();
|
public ArrayList<User> users = new ArrayList<User>();
|
||||||
@ -1482,6 +1613,15 @@ public class TLRPC {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class TL_inputPrivacyKeyStatusTimestamp extends TLObject {
|
||||||
|
public static int constructor = 0x4f96cb18;
|
||||||
|
|
||||||
|
|
||||||
|
public void serializeToStream(AbsSerializedData stream) {
|
||||||
|
stream.writeInt32(constructor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static class photos_Photos extends TLObject {
|
public static class photos_Photos extends TLObject {
|
||||||
public ArrayList<Photo> photos = new ArrayList<Photo>();
|
public ArrayList<Photo> photos = new ArrayList<Photo>();
|
||||||
public ArrayList<User> users = new ArrayList<User>();
|
public ArrayList<User> users = new ArrayList<User>();
|
||||||
@ -2841,6 +2981,92 @@ public class TLRPC {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class InputPrivacyRule extends TLObject {
|
||||||
|
public ArrayList<InputUser> users = new ArrayList<InputUser>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TL_inputPrivacyValueDisallowUsers extends InputPrivacyRule {
|
||||||
|
public static int constructor = 0x90110467;
|
||||||
|
|
||||||
|
|
||||||
|
public void readParams(AbsSerializedData stream) {
|
||||||
|
stream.readInt32();
|
||||||
|
int count = stream.readInt32();
|
||||||
|
for (int a = 0; a < count; a++) {
|
||||||
|
users.add((InputUser)TLClassStore.Instance().TLdeserialize(stream, stream.readInt32()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void serializeToStream(AbsSerializedData stream) {
|
||||||
|
stream.writeInt32(constructor);
|
||||||
|
stream.writeInt32(0x1cb5c415);
|
||||||
|
int count = users.size();
|
||||||
|
stream.writeInt32(count);
|
||||||
|
for (InputUser user : users) {
|
||||||
|
user.serializeToStream(stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TL_inputPrivacyValueDisallowAll extends InputPrivacyRule {
|
||||||
|
public static int constructor = 0xd66b66c9;
|
||||||
|
|
||||||
|
|
||||||
|
public void serializeToStream(AbsSerializedData stream) {
|
||||||
|
stream.writeInt32(constructor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TL_inputPrivacyValueDisallowContacts extends InputPrivacyRule {
|
||||||
|
public static int constructor = 0xba52007;
|
||||||
|
|
||||||
|
|
||||||
|
public void serializeToStream(AbsSerializedData stream) {
|
||||||
|
stream.writeInt32(constructor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TL_inputPrivacyValueAllowAll extends InputPrivacyRule {
|
||||||
|
public static int constructor = 0x184b35ce;
|
||||||
|
|
||||||
|
|
||||||
|
public void serializeToStream(AbsSerializedData stream) {
|
||||||
|
stream.writeInt32(constructor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TL_inputPrivacyValueAllowContacts extends InputPrivacyRule {
|
||||||
|
public static int constructor = 0xd09e07b;
|
||||||
|
|
||||||
|
|
||||||
|
public void serializeToStream(AbsSerializedData stream) {
|
||||||
|
stream.writeInt32(constructor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TL_inputPrivacyValueAllowUsers extends InputPrivacyRule {
|
||||||
|
public static int constructor = 0x131cc67f;
|
||||||
|
|
||||||
|
|
||||||
|
public void readParams(AbsSerializedData stream) {
|
||||||
|
stream.readInt32();
|
||||||
|
int count = stream.readInt32();
|
||||||
|
for (int a = 0; a < count; a++) {
|
||||||
|
users.add((InputUser)TLClassStore.Instance().TLdeserialize(stream, stream.readInt32()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void serializeToStream(AbsSerializedData stream) {
|
||||||
|
stream.writeInt32(constructor);
|
||||||
|
stream.writeInt32(0x1cb5c415);
|
||||||
|
int count = users.size();
|
||||||
|
stream.writeInt32(count);
|
||||||
|
for (InputUser user : users) {
|
||||||
|
user.serializeToStream(stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static class InputMedia extends TLObject {
|
public static class InputMedia extends TLObject {
|
||||||
public String phone_number;
|
public String phone_number;
|
||||||
public String first_name;
|
public String first_name;
|
||||||
@ -3449,6 +3675,9 @@ public class TLRPC {
|
|||||||
public long random_id;
|
public long random_id;
|
||||||
public ArrayList<TL_dcOption> dc_options = new ArrayList<TL_dcOption>();
|
public ArrayList<TL_dcOption> dc_options = new ArrayList<TL_dcOption>();
|
||||||
public ChatParticipants participants;
|
public ChatParticipants participants;
|
||||||
|
public String phone;
|
||||||
|
public TL_privacyKeyStatusTimestamp key;
|
||||||
|
public ArrayList<PrivacyRule> rules = new ArrayList<PrivacyRule>();
|
||||||
public EncryptedChat chat;
|
public EncryptedChat chat;
|
||||||
public boolean blocked;
|
public boolean blocked;
|
||||||
public long auth_key_id;
|
public long auth_key_id;
|
||||||
@ -3781,6 +4010,47 @@ public class TLRPC {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class TL_updateUserPhone extends Update {
|
||||||
|
public static int constructor = 0x12b9417b;
|
||||||
|
|
||||||
|
|
||||||
|
public void readParams(AbsSerializedData stream) {
|
||||||
|
user_id = stream.readInt32();
|
||||||
|
phone = stream.readString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void serializeToStream(AbsSerializedData stream) {
|
||||||
|
stream.writeInt32(constructor);
|
||||||
|
stream.writeInt32(user_id);
|
||||||
|
stream.writeString(phone);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TL_updatePrivacy extends Update {
|
||||||
|
public static int constructor = 0xee3b272a;
|
||||||
|
|
||||||
|
|
||||||
|
public void readParams(AbsSerializedData stream) {
|
||||||
|
key = (TL_privacyKeyStatusTimestamp)TLClassStore.Instance().TLdeserialize(stream, stream.readInt32());
|
||||||
|
stream.readInt32();
|
||||||
|
int count = stream.readInt32();
|
||||||
|
for (int a = 0; a < count; a++) {
|
||||||
|
rules.add((PrivacyRule)TLClassStore.Instance().TLdeserialize(stream, stream.readInt32()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void serializeToStream(AbsSerializedData stream) {
|
||||||
|
stream.writeInt32(constructor);
|
||||||
|
key.serializeToStream(stream);
|
||||||
|
stream.writeInt32(0x1cb5c415);
|
||||||
|
int count = rules.size();
|
||||||
|
stream.writeInt32(count);
|
||||||
|
for (PrivacyRule rule : rules) {
|
||||||
|
rule.serializeToStream(stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static class TL_updateEncryption extends Update {
|
public static class TL_updateEncryption extends Update {
|
||||||
public static int constructor = 0xb4a2e88d;
|
public static int constructor = 0xb4a2e88d;
|
||||||
|
|
||||||
@ -4076,10 +4346,14 @@ public class TLRPC {
|
|||||||
public static class DecryptedMessageAction extends TLObject {
|
public static class DecryptedMessageAction extends TLObject {
|
||||||
public int start_seq_no;
|
public int start_seq_no;
|
||||||
public int end_seq_no;
|
public int end_seq_no;
|
||||||
public int layer;
|
|
||||||
public int ttl_seconds;
|
public int ttl_seconds;
|
||||||
|
public int layer;
|
||||||
public ArrayList<Long> random_ids = new ArrayList<Long>();
|
public ArrayList<Long> random_ids = new ArrayList<Long>();
|
||||||
|
public long exchange_id;
|
||||||
|
public long key_fingerprint;
|
||||||
|
public byte[] g_b;
|
||||||
public SendMessageAction action;
|
public SendMessageAction action;
|
||||||
|
public byte[] g_a;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class TL_decryptedMessageActionSetMessageTTL extends DecryptedMessageAction {
|
public static class TL_decryptedMessageActionSetMessageTTL extends DecryptedMessageAction {
|
||||||
@ -4103,6 +4377,24 @@ public class TLRPC {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class TL_decryptedMessageActionAcceptKey extends DecryptedMessageAction {
|
||||||
|
public static int constructor = 0x6fe1735b;
|
||||||
|
|
||||||
|
|
||||||
|
public void readParams(AbsSerializedData stream) {
|
||||||
|
exchange_id = stream.readInt64();
|
||||||
|
g_b = stream.readByteArray();
|
||||||
|
key_fingerprint = stream.readInt64();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void serializeToStream(AbsSerializedData stream) {
|
||||||
|
stream.writeInt32(constructor);
|
||||||
|
stream.writeInt64(exchange_id);
|
||||||
|
stream.writeByteArray(g_b);
|
||||||
|
stream.writeInt64(key_fingerprint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static class TL_decryptedMessageActionResend extends DecryptedMessageAction {
|
public static class TL_decryptedMessageActionResend extends DecryptedMessageAction {
|
||||||
public static int constructor = 0x511110b0;
|
public static int constructor = 0x511110b0;
|
||||||
|
|
||||||
@ -4156,6 +4448,22 @@ public class TLRPC {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class TL_decryptedMessageActionRequestKey extends DecryptedMessageAction {
|
||||||
|
public static int constructor = 0xf3c9611b;
|
||||||
|
|
||||||
|
|
||||||
|
public void readParams(AbsSerializedData stream) {
|
||||||
|
exchange_id = stream.readInt64();
|
||||||
|
g_a = stream.readByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void serializeToStream(AbsSerializedData stream) {
|
||||||
|
stream.writeInt32(constructor);
|
||||||
|
stream.writeInt64(exchange_id);
|
||||||
|
stream.writeByteArray(g_a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static class TL_decryptedMessageActionTyping extends DecryptedMessageAction {
|
public static class TL_decryptedMessageActionTyping extends DecryptedMessageAction {
|
||||||
public static int constructor = 0xccb27641;
|
public static int constructor = 0xccb27641;
|
||||||
|
|
||||||
@ -4627,6 +4935,107 @@ public class TLRPC {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class TL_account_getPrivacy extends TLObject {
|
||||||
|
public static int constructor = 0xdadbc950;
|
||||||
|
|
||||||
|
public TL_inputPrivacyKeyStatusTimestamp key;
|
||||||
|
|
||||||
|
public Class responseClass () {
|
||||||
|
return TL_account_privacyRules.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void readParams(AbsSerializedData stream) {
|
||||||
|
key = (TL_inputPrivacyKeyStatusTimestamp)TLClassStore.Instance().TLdeserialize(stream, stream.readInt32());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void serializeToStream(AbsSerializedData stream) {
|
||||||
|
stream.writeInt32(constructor);
|
||||||
|
key.serializeToStream(stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TL_account_setPrivacy extends TLObject {
|
||||||
|
public static int constructor = 0xc9f81ce8;
|
||||||
|
|
||||||
|
public TL_inputPrivacyKeyStatusTimestamp key;
|
||||||
|
public ArrayList<InputPrivacyRule> rules = new ArrayList<InputPrivacyRule>();
|
||||||
|
|
||||||
|
public Class responseClass () {
|
||||||
|
return TL_account_privacyRules.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void readParams(AbsSerializedData stream) {
|
||||||
|
key = (TL_inputPrivacyKeyStatusTimestamp)TLClassStore.Instance().TLdeserialize(stream, stream.readInt32());
|
||||||
|
stream.readInt32();
|
||||||
|
int count = stream.readInt32();
|
||||||
|
for (int a = 0; a < count; a++) {
|
||||||
|
rules.add((InputPrivacyRule)TLClassStore.Instance().TLdeserialize(stream, stream.readInt32()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void serializeToStream(AbsSerializedData stream) {
|
||||||
|
stream.writeInt32(constructor);
|
||||||
|
key.serializeToStream(stream);
|
||||||
|
stream.writeInt32(0x1cb5c415);
|
||||||
|
int count = rules.size();
|
||||||
|
stream.writeInt32(count);
|
||||||
|
for (InputPrivacyRule rule : rules) {
|
||||||
|
rule.serializeToStream(stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TL_account_deleteAccount extends TLObject {
|
||||||
|
public static int constructor = 0x418d4e0b;
|
||||||
|
|
||||||
|
public String reason;
|
||||||
|
|
||||||
|
public Class responseClass () {
|
||||||
|
return Bool.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void readParams(AbsSerializedData stream) {
|
||||||
|
reason = stream.readString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void serializeToStream(AbsSerializedData stream) {
|
||||||
|
stream.writeInt32(constructor);
|
||||||
|
stream.writeString(reason);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TL_account_getAccountTTL extends TLObject {
|
||||||
|
public static int constructor = 0x8fc711d;
|
||||||
|
|
||||||
|
|
||||||
|
public Class responseClass () {
|
||||||
|
return TL_accountDaysTTL.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void serializeToStream(AbsSerializedData stream) {
|
||||||
|
stream.writeInt32(constructor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TL_account_setAccountTTL extends TLObject {
|
||||||
|
public static int constructor = 0x2442485e;
|
||||||
|
|
||||||
|
public TL_accountDaysTTL ttl;
|
||||||
|
|
||||||
|
public Class responseClass () {
|
||||||
|
return Bool.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void readParams(AbsSerializedData stream) {
|
||||||
|
ttl = (TL_accountDaysTTL)TLClassStore.Instance().TLdeserialize(stream, stream.readInt32());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void serializeToStream(AbsSerializedData stream) {
|
||||||
|
stream.writeInt32(constructor);
|
||||||
|
ttl.serializeToStream(stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static class TL_account_checkUsername extends TLObject {
|
public static class TL_account_checkUsername extends TLObject {
|
||||||
public static int constructor = 0x2714d86c;
|
public static int constructor = 0x2714d86c;
|
||||||
|
|
||||||
@ -4665,6 +5074,69 @@ public class TLRPC {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class TL_contacts_resolveUsername extends TLObject {
|
||||||
|
public static int constructor = 0xbf0131c;
|
||||||
|
|
||||||
|
public String username;
|
||||||
|
|
||||||
|
public Class responseClass () {
|
||||||
|
return User.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void readParams(AbsSerializedData stream) {
|
||||||
|
username = stream.readString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void serializeToStream(AbsSerializedData stream) {
|
||||||
|
stream.writeInt32(constructor);
|
||||||
|
stream.writeString(username);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TL_account_sendChangePhoneCode extends TLObject {
|
||||||
|
public static int constructor = 0xa407a8f4;
|
||||||
|
|
||||||
|
public String phone_number;
|
||||||
|
|
||||||
|
public Class responseClass () {
|
||||||
|
return TL_account_sentChangePhoneCode.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void readParams(AbsSerializedData stream) {
|
||||||
|
phone_number = stream.readString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void serializeToStream(AbsSerializedData stream) {
|
||||||
|
stream.writeInt32(constructor);
|
||||||
|
stream.writeString(phone_number);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TL_account_changePhone extends TLObject {
|
||||||
|
public static int constructor = 0x70c32edb;
|
||||||
|
|
||||||
|
public String phone_number;
|
||||||
|
public String phone_code_hash;
|
||||||
|
public String phone_code;
|
||||||
|
|
||||||
|
public Class responseClass () {
|
||||||
|
return User.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void readParams(AbsSerializedData stream) {
|
||||||
|
phone_number = stream.readString();
|
||||||
|
phone_code_hash = stream.readString();
|
||||||
|
phone_code = stream.readString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void serializeToStream(AbsSerializedData stream) {
|
||||||
|
stream.writeInt32(constructor);
|
||||||
|
stream.writeString(phone_number);
|
||||||
|
stream.writeString(phone_code_hash);
|
||||||
|
stream.writeString(phone_code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static class InputAudio extends TLObject {
|
public static class InputAudio extends TLObject {
|
||||||
public long id;
|
public long id;
|
||||||
public long access_hash;
|
public long access_hash;
|
||||||
@ -5546,6 +6018,24 @@ public class TLRPC {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class TL_account_sentChangePhoneCode extends TLObject {
|
||||||
|
public static int constructor = 0xa4f58c4c;
|
||||||
|
|
||||||
|
public String phone_code_hash;
|
||||||
|
public int send_call_timeout;
|
||||||
|
|
||||||
|
public void readParams(AbsSerializedData stream) {
|
||||||
|
phone_code_hash = stream.readString();
|
||||||
|
send_call_timeout = stream.readInt32();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void serializeToStream(AbsSerializedData stream) {
|
||||||
|
stream.writeInt32(constructor);
|
||||||
|
stream.writeString(phone_code_hash);
|
||||||
|
stream.writeInt32(send_call_timeout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static class InputFile extends TLObject {
|
public static class InputFile extends TLObject {
|
||||||
public long id;
|
public long id;
|
||||||
public int parts;
|
public int parts;
|
||||||
@ -6267,6 +6757,21 @@ public class TLRPC {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class TL_accountDaysTTL extends TLObject {
|
||||||
|
public static int constructor = 0xb8d0afdf;
|
||||||
|
|
||||||
|
public int days;
|
||||||
|
|
||||||
|
public void readParams(AbsSerializedData stream) {
|
||||||
|
days = stream.readInt32();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void serializeToStream(AbsSerializedData stream) {
|
||||||
|
stream.writeInt32(constructor);
|
||||||
|
stream.writeInt32(days);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static class InputPeer extends TLObject {
|
public static class InputPeer extends TLObject {
|
||||||
public int user_id;
|
public int user_id;
|
||||||
public int chat_id;
|
public int chat_id;
|
||||||
@ -7020,6 +7525,18 @@ public class TLRPC {
|
|||||||
public static class TL_contacts_getStatuses extends TLObject {
|
public static class TL_contacts_getStatuses extends TLObject {
|
||||||
public static int constructor = 0xc4a353ee;
|
public static int constructor = 0xc4a353ee;
|
||||||
|
|
||||||
|
public ArrayList<TL_contactStatus> id = new ArrayList<TL_contactStatus>();
|
||||||
|
|
||||||
|
public Class responseClass () {
|
||||||
|
return Vector.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void parseVector(Vector vector, AbsSerializedData data) {
|
||||||
|
int size = data.readInt32();
|
||||||
|
for (int a = 0; a < size; a++) {
|
||||||
|
vector.objects.add(TLClassStore.Instance().TLdeserialize(data, data.readInt32()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void serializeToStream(AbsSerializedData stream) {
|
public void serializeToStream(AbsSerializedData stream) {
|
||||||
stream.writeInt32(constructor);
|
stream.writeInt32(constructor);
|
||||||
@ -8431,6 +8948,38 @@ public class TLRPC {
|
|||||||
|
|
||||||
//manually created
|
//manually created
|
||||||
|
|
||||||
|
public static class TL_decryptedMessageHolder extends TLObject {
|
||||||
|
public static int constructor = 0x555555F9;
|
||||||
|
|
||||||
|
public long random_id;
|
||||||
|
public int date;
|
||||||
|
public TL_decryptedMessageLayer layer;
|
||||||
|
public EncryptedFile file;
|
||||||
|
public boolean new_key_used;
|
||||||
|
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
new_key_used = stream.readBool();
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
stream.writeBool(new_key_used);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static class TL_messages_sendEncryptedService extends TLObject {
|
public static class TL_messages_sendEncryptedService extends TLObject {
|
||||||
public static int constructor = 0x32d439a4;
|
public static int constructor = 0x32d439a4;
|
||||||
|
|
||||||
@ -8715,6 +9264,15 @@ public class TLRPC {
|
|||||||
public int expires;
|
public int expires;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class TL_userStatusLastWeek extends UserStatus {
|
||||||
|
public static int constructor = 0x7bf09fc;
|
||||||
|
|
||||||
|
|
||||||
|
public void serializeToStream(AbsSerializedData stream) {
|
||||||
|
stream.writeInt32(constructor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static class TL_userStatusEmpty extends UserStatus {
|
public static class TL_userStatusEmpty extends UserStatus {
|
||||||
public static int constructor = 0x9d05049;
|
public static int constructor = 0x9d05049;
|
||||||
|
|
||||||
@ -8724,6 +9282,15 @@ public class TLRPC {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class TL_userStatusLastMonth extends UserStatus {
|
||||||
|
public static int constructor = 0x77ebc742;
|
||||||
|
|
||||||
|
|
||||||
|
public void serializeToStream(AbsSerializedData stream) {
|
||||||
|
stream.writeInt32(constructor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static class TL_userStatusOnline extends UserStatus {
|
public static class TL_userStatusOnline extends UserStatus {
|
||||||
public static int constructor = 0xedb93949;
|
public static int constructor = 0xedb93949;
|
||||||
|
|
||||||
@ -8738,6 +9305,15 @@ public class TLRPC {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class TL_userStatusRecently extends UserStatus {
|
||||||
|
public static int constructor = 0xe26f42f1;
|
||||||
|
|
||||||
|
|
||||||
|
public void serializeToStream(AbsSerializedData stream) {
|
||||||
|
stream.writeInt32(constructor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static class TL_userStatusOffline extends UserStatus {
|
public static class TL_userStatusOffline extends UserStatus {
|
||||||
public static int constructor = 0x8c703f;
|
public static int constructor = 0x8c703f;
|
||||||
|
|
||||||
@ -9553,6 +10129,13 @@ public class TLRPC {
|
|||||||
public int layer;
|
public int layer;
|
||||||
public int seq_in;
|
public int seq_in;
|
||||||
public int seq_out;
|
public int seq_out;
|
||||||
|
public byte[] key_hash;
|
||||||
|
public short key_use_count_in;
|
||||||
|
public short key_use_count_out;
|
||||||
|
public long exchange_id;
|
||||||
|
public int key_create_date;
|
||||||
|
public long future_key_fingerprint;
|
||||||
|
public byte[] future_auth_key;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class FileLocation extends TLObject {
|
public static class FileLocation extends TLObject {
|
||||||
@ -9850,13 +10433,15 @@ public class TLRPC {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class invokeWithLayer18 extends TLObject {
|
public static class invokeWithLayer extends TLObject {
|
||||||
public static int constructor = 0x1c900537;
|
public static int constructor = 0xda9b0d0d;
|
||||||
|
|
||||||
|
public int layer = 20;
|
||||||
public TLObject query;
|
public TLObject query;
|
||||||
|
|
||||||
public void serializeToStream(AbsSerializedData stream) {
|
public void serializeToStream(AbsSerializedData stream) {
|
||||||
stream.writeInt32(constructor);
|
stream.writeInt32(constructor);
|
||||||
|
stream.writeInt32(layer);
|
||||||
query.serializeToStream(stream);
|
query.serializeToStream(stream);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -9967,6 +10552,45 @@ public class TLRPC {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class TL_decryptedMessageActionCommitKey extends DecryptedMessageAction {
|
||||||
|
public static int constructor = 0xec2e0b9b;
|
||||||
|
|
||||||
|
|
||||||
|
public void readParams(AbsSerializedData stream) {
|
||||||
|
exchange_id = stream.readInt64();
|
||||||
|
key_fingerprint = stream.readInt64();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void serializeToStream(AbsSerializedData stream) {
|
||||||
|
stream.writeInt32(constructor);
|
||||||
|
stream.writeInt64(exchange_id);
|
||||||
|
stream.writeInt64(key_fingerprint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TL_decryptedMessageActionAbortKey extends DecryptedMessageAction {
|
||||||
|
public static int constructor = 0xdd05ec6b;
|
||||||
|
|
||||||
|
|
||||||
|
public void readParams(AbsSerializedData stream) {
|
||||||
|
exchange_id = stream.readInt64();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void serializeToStream(AbsSerializedData stream) {
|
||||||
|
stream.writeInt32(constructor);
|
||||||
|
stream.writeInt64(exchange_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TL_decryptedMessageActionNoop extends DecryptedMessageAction {
|
||||||
|
public static int constructor = 0xa82fdd63;
|
||||||
|
|
||||||
|
|
||||||
|
public void serializeToStream(AbsSerializedData stream) {
|
||||||
|
stream.writeInt32(constructor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static class TL_decryptedMessageActionScreenshotMessages extends DecryptedMessageAction {
|
public static class TL_decryptedMessageActionScreenshotMessages extends DecryptedMessageAction {
|
||||||
public static int constructor = 0x8ac1f475;
|
public static int constructor = 0x8ac1f475;
|
||||||
|
|
||||||
|
@ -13,7 +13,6 @@ import android.content.SharedPreferences;
|
|||||||
import android.util.Base64;
|
import android.util.Base64;
|
||||||
|
|
||||||
import org.telegram.android.MessagesStorage;
|
import org.telegram.android.MessagesStorage;
|
||||||
import org.telegram.ui.ApplicationLoader;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ import android.content.Context;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Environment;
|
import android.os.Environment;
|
||||||
@ -27,8 +28,6 @@ import net.hockeyapp.android.CrashManager;
|
|||||||
import net.hockeyapp.android.CrashManagerListener;
|
import net.hockeyapp.android.CrashManagerListener;
|
||||||
import net.hockeyapp.android.UpdateManager;
|
import net.hockeyapp.android.UpdateManager;
|
||||||
|
|
||||||
import org.telegram.ui.ApplicationLoader;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@ -107,13 +106,13 @@ public class Utilities {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public native static long doPQNative(long _what);
|
public native static long doPQNative(long _what);
|
||||||
public native static void loadBitmap(String path, int[] bitmap, int scale, int format, int width, int height);
|
public native static void loadBitmap(String path, Bitmap bitmap, int scale, int width, int height, int stride);
|
||||||
public native static void blurBitmap(Object bitmap, int radius);
|
public native static void blurBitmap(Object bitmap, int radius);
|
||||||
public native static int convertVideoFrame(ByteBuffer src, ByteBuffer dest, int destFormat, int width, int height, int padding, int swap);
|
public native static int convertVideoFrame(ByteBuffer src, ByteBuffer dest, int destFormat, int width, int height, int padding, int swap);
|
||||||
private native static void aesIgeEncryption(ByteBuffer buffer, byte[] key, byte[] iv, boolean encrypt, int offset, int length);
|
private native static void aesIgeEncryption(ByteBuffer buffer, byte[] key, byte[] iv, boolean encrypt, int offset, int length);
|
||||||
|
|
||||||
public static void aesIgeEncryption(ByteBuffer buffer, byte[] key, byte[] iv, boolean encrypt, boolean changeIv, int offset, int length) {
|
public static void aesIgeEncryption(ByteBuffer buffer, byte[] key, byte[] iv, boolean encrypt, boolean changeIv, int offset, int length) {
|
||||||
aesIgeEncryption(buffer, key, changeIv ? iv : iv.clone(), encrypt, offset, length);
|
aesIgeEncryption(buffer, key, changeIv ? iv : (byte [])iv.clone(), encrypt, offset, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Integer parseInt(String value) {
|
public static Integer parseInt(String value) {
|
||||||
@ -639,7 +638,7 @@ public class Utilities {
|
|||||||
builder.append(" ");
|
builder.append(" ");
|
||||||
}
|
}
|
||||||
query.trim();
|
query.trim();
|
||||||
builder.append(Html.fromHtml("<font color=\"#357aa8\">" + query + "</font>"));
|
builder.append(Html.fromHtml("<font color=\"#4d83b3\">" + query + "</font>"));
|
||||||
|
|
||||||
lastIndex = end;
|
lastIndex = end;
|
||||||
}
|
}
|
||||||
|
@ -6,17 +6,17 @@
|
|||||||
* Copyright Nikolai Kudashov, 2013-2014.
|
* Copyright Nikolai Kudashov, 2013-2014.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.telegram.ui.Views.ActionBar;
|
package org.telegram.ui.ActionBar;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.os.Build;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.AttributeSet;
|
|
||||||
import android.view.Gravity;
|
import android.view.Gravity;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.MotionEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
@ -24,7 +24,7 @@ import android.widget.TextView;
|
|||||||
import org.telegram.android.AndroidUtilities;
|
import org.telegram.android.AndroidUtilities;
|
||||||
import org.telegram.messenger.R;
|
import org.telegram.messenger.R;
|
||||||
|
|
||||||
public class ActionBarLayer extends FrameLayout {
|
public class ActionBar extends FrameLayout {
|
||||||
|
|
||||||
public static class ActionBarMenuOnItemClick {
|
public static class ActionBarMenuOnItemClick {
|
||||||
public void onItemClick(int id) {
|
public void onItemClick(int id) {
|
||||||
@ -36,96 +36,49 @@ public class ActionBarLayer extends FrameLayout {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private FrameLayout backButtonFrameLayout;
|
private FrameLayout titleFrameLayout;
|
||||||
private ImageView logoImageView;
|
|
||||||
private ImageView backButtonImageView;
|
private ImageView backButtonImageView;
|
||||||
private TextView titleTextView;
|
private TextView titleTextView;
|
||||||
private TextView subTitleTextView;
|
private TextView subTitleTextView;
|
||||||
|
private View actionModeTop;
|
||||||
private ActionBarMenu menu;
|
private ActionBarMenu menu;
|
||||||
private ActionBarMenu actionMode;
|
private ActionBarMenu actionMode;
|
||||||
private int logoResourceId;
|
private boolean occupyStatusBar = Build.VERSION.SDK_INT >= 21;
|
||||||
private int backResourceId;
|
|
||||||
protected ActionBar parentActionBar;
|
private boolean allowOverlayTitle;
|
||||||
private boolean oldUseLogo;
|
private CharSequence lastTitle;
|
||||||
private boolean oldUseBack;
|
private boolean showingOverlayTitle;
|
||||||
private View actionOverlay;
|
|
||||||
protected boolean isSearchFieldVisible;
|
protected boolean isSearchFieldVisible;
|
||||||
protected int itemsBackgroundResourceId;
|
protected int itemsBackgroundResourceId;
|
||||||
private boolean isBackOverlayVisible;
|
private boolean isBackOverlayVisible;
|
||||||
protected BaseFragment parentFragment;
|
protected BaseFragment parentFragment;
|
||||||
public ActionBarMenuOnItemClick actionBarMenuOnItemClick;
|
public ActionBarMenuOnItemClick actionBarMenuOnItemClick;
|
||||||
private int leftMargin = 0;
|
private int extraHeight;
|
||||||
|
|
||||||
public ActionBarLayer(Context context, ActionBar actionBar) {
|
public ActionBar(Context context) {
|
||||||
super(context);
|
super(context);
|
||||||
parentActionBar = actionBar;
|
titleFrameLayout = new FrameLayout(context);
|
||||||
backButtonFrameLayout = new FrameLayout(context);
|
addView(titleFrameLayout);
|
||||||
addView(backButtonFrameLayout);
|
FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams)titleFrameLayout.getLayoutParams();
|
||||||
FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams)backButtonFrameLayout.getLayoutParams();
|
|
||||||
layoutParams.width = LayoutParams.WRAP_CONTENT;
|
layoutParams.width = LayoutParams.WRAP_CONTENT;
|
||||||
layoutParams.height = LayoutParams.FILL_PARENT;
|
layoutParams.height = LayoutParams.FILL_PARENT;
|
||||||
layoutParams.gravity = Gravity.TOP | Gravity.LEFT;
|
layoutParams.gravity = Gravity.TOP | Gravity.LEFT;
|
||||||
backButtonFrameLayout.setLayoutParams(layoutParams);
|
titleFrameLayout.setLayoutParams(layoutParams);
|
||||||
backButtonFrameLayout.setPadding(0, 0, AndroidUtilities.dp(4), 0);
|
titleFrameLayout.setPadding(0, 0, AndroidUtilities.dp(4), 0);
|
||||||
backButtonFrameLayout.setOnClickListener(new OnClickListener() {
|
titleFrameLayout.setEnabled(false);
|
||||||
@Override
|
|
||||||
public void onClick(View view) {
|
|
||||||
if (isSearchFieldVisible) {
|
|
||||||
closeSearchField();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (actionBarMenuOnItemClick != null) {
|
|
||||||
actionBarMenuOnItemClick.onItemClick(-1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
backButtonFrameLayout.setEnabled(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ActionBarLayer(Context context) {
|
|
||||||
super(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ActionBarLayer(Context context, AttributeSet attrs) {
|
|
||||||
super(context, attrs);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ActionBarLayer(Context context, AttributeSet attrs, int defStyleAttr) {
|
|
||||||
super(context, attrs, defStyleAttr);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setExtraLeftMargin(int margin) {
|
|
||||||
leftMargin = margin;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void positionBackImage(int height) {
|
private void positionBackImage(int height) {
|
||||||
if (backButtonImageView != null) {
|
if (backButtonImageView != null) {
|
||||||
LayoutParams layoutParams = (LayoutParams)backButtonImageView.getLayoutParams();
|
LayoutParams layoutParams = (LayoutParams)backButtonImageView.getLayoutParams();
|
||||||
layoutParams.width = LayoutParams.WRAP_CONTENT;
|
layoutParams.width = AndroidUtilities.dp(54);
|
||||||
layoutParams.height = LayoutParams.WRAP_CONTENT;
|
layoutParams.height = height;
|
||||||
layoutParams.gravity = Gravity.TOP | Gravity.LEFT;
|
layoutParams.gravity = Gravity.TOP | Gravity.LEFT;
|
||||||
layoutParams.setMargins(AndroidUtilities.dp(3 + leftMargin), (height - backButtonImageView.getDrawable().getIntrinsicHeight()) / 2, 0, 0);
|
|
||||||
backButtonImageView.setLayoutParams(layoutParams);
|
backButtonImageView.setLayoutParams(layoutParams);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void positionLogoImage(int height) {
|
|
||||||
if (logoImageView != null && logoImageView.getDrawable() != null) {
|
|
||||||
LayoutParams layoutParams = (LayoutParams) logoImageView.getLayoutParams();
|
|
||||||
if (!AndroidUtilities.isTablet() && getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
|
||||||
layoutParams.width = (int)(logoImageView.getDrawable().getIntrinsicWidth() / 1.3f);
|
|
||||||
layoutParams.height = (int)(logoImageView.getDrawable().getIntrinsicHeight() / 1.3f);
|
|
||||||
layoutParams.setMargins(AndroidUtilities.dp(12), (height - layoutParams.height) / 2, 0, 0);
|
|
||||||
} else {
|
|
||||||
layoutParams.width = logoImageView.getDrawable().getIntrinsicWidth();
|
|
||||||
layoutParams.height = logoImageView.getDrawable().getIntrinsicHeight();
|
|
||||||
layoutParams.setMargins(AndroidUtilities.dp(12), (height - layoutParams.width) / 2, 0, 0);
|
|
||||||
}
|
|
||||||
layoutParams.gravity = Gravity.TOP | Gravity.LEFT;
|
|
||||||
logoImageView.setLayoutParams(layoutParams);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void positionTitle(int width, int height) {
|
private void positionTitle(int width, int height) {
|
||||||
int offset = AndroidUtilities.dp(2);
|
int offset = AndroidUtilities.dp(2);
|
||||||
if (!AndroidUtilities.isTablet() && getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
if (!AndroidUtilities.isTablet() && getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
||||||
@ -137,9 +90,9 @@ public class ActionBarLayer extends FrameLayout {
|
|||||||
|
|
||||||
if (titleTextView != null && titleTextView.getVisibility() == VISIBLE) {
|
if (titleTextView != null && titleTextView.getVisibility() == VISIBLE) {
|
||||||
if (!AndroidUtilities.isTablet() && getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
if (!AndroidUtilities.isTablet() && getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
||||||
titleTextView.setTextSize(16);
|
|
||||||
} else {
|
|
||||||
titleTextView.setTextSize(18);
|
titleTextView.setTextSize(18);
|
||||||
|
} else {
|
||||||
|
titleTextView.setTextSize(20);
|
||||||
}
|
}
|
||||||
|
|
||||||
layoutParams = (LayoutParams) titleTextView.getLayoutParams();
|
layoutParams = (LayoutParams) titleTextView.getLayoutParams();
|
||||||
@ -152,9 +105,9 @@ public class ActionBarLayer extends FrameLayout {
|
|||||||
}
|
}
|
||||||
if (subTitleTextView != null && subTitleTextView.getVisibility() == VISIBLE) {
|
if (subTitleTextView != null && subTitleTextView.getVisibility() == VISIBLE) {
|
||||||
if (!AndroidUtilities.isTablet() && getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
if (!AndroidUtilities.isTablet() && getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
||||||
subTitleTextView.setTextSize(12);
|
|
||||||
} else {
|
|
||||||
subTitleTextView.setTextSize(14);
|
subTitleTextView.setTextSize(14);
|
||||||
|
} else {
|
||||||
|
subTitleTextView.setTextSize(16);
|
||||||
}
|
}
|
||||||
|
|
||||||
layoutParams = (LayoutParams) subTitleTextView.getLayoutParams();
|
layoutParams = (LayoutParams) subTitleTextView.getLayoutParams();
|
||||||
@ -167,13 +120,17 @@ public class ActionBarLayer extends FrameLayout {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int x = 0;
|
int x = 0;
|
||||||
if (logoImageView == null || logoImageView.getVisibility() == GONE) {
|
if (backButtonImageView != null) {
|
||||||
x = AndroidUtilities.dp(16 + leftMargin);
|
if (AndroidUtilities.isTablet()) {
|
||||||
} else {
|
x = AndroidUtilities.dp(80);
|
||||||
if (!AndroidUtilities.isTablet() && getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
|
||||||
x = AndroidUtilities.dp(22 + leftMargin) + (logoImageView.getDrawable() != null ? (int)(logoImageView.getDrawable().getIntrinsicWidth() / 1.3f) : 0);
|
|
||||||
} else {
|
} else {
|
||||||
x = AndroidUtilities.dp(22 + leftMargin) + (logoImageView.getDrawable() != null ? logoImageView.getDrawable().getIntrinsicWidth() : 0);
|
x = AndroidUtilities.dp(72);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (AndroidUtilities.isTablet()) {
|
||||||
|
x = AndroidUtilities.dp(26);
|
||||||
|
} else {
|
||||||
|
x = AndroidUtilities.dp(18);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,9 +142,11 @@ public class ActionBarLayer extends FrameLayout {
|
|||||||
layoutParams = (LayoutParams) titleTextView.getLayoutParams();
|
layoutParams = (LayoutParams) titleTextView.getLayoutParams();
|
||||||
layoutParams.width = LayoutParams.MATCH_PARENT;
|
layoutParams.width = LayoutParams.MATCH_PARENT;
|
||||||
layoutParams.height = titleTextView.getMeasuredHeight();
|
layoutParams.height = titleTextView.getMeasuredHeight();
|
||||||
int y = (height - titleTextView.getMeasuredHeight()) / 2;
|
int y;
|
||||||
if (subTitleTextView != null && subTitleTextView.getVisibility() == VISIBLE) {
|
if (subTitleTextView != null && subTitleTextView.getVisibility() == VISIBLE) {
|
||||||
y = (height / 2 - titleTextView.getMeasuredHeight()) / 2 + offset;
|
y = (height / 2 - titleTextView.getMeasuredHeight()) / 2 + offset;
|
||||||
|
} else {
|
||||||
|
y = (height - titleTextView.getMeasuredHeight()) / 2 - AndroidUtilities.dp(1);
|
||||||
}
|
}
|
||||||
layoutParams.setMargins(x, y, 0, 0);
|
layoutParams.setMargins(x, y, 0, 0);
|
||||||
titleTextView.setLayoutParams(layoutParams);
|
titleTextView.setLayoutParams(layoutParams);
|
||||||
@ -200,9 +159,10 @@ public class ActionBarLayer extends FrameLayout {
|
|||||||
subTitleTextView.setLayoutParams(layoutParams);
|
subTitleTextView.setLayoutParams(layoutParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
ViewGroup.LayoutParams layoutParams1 = backButtonFrameLayout.getLayoutParams();
|
MarginLayoutParams layoutParams1 = (MarginLayoutParams) titleFrameLayout.getLayoutParams();
|
||||||
layoutParams1.width = x + maxTextWidth + (isSearchFieldVisible ? 0 : AndroidUtilities.dp(6));
|
layoutParams1.width = x + maxTextWidth + (isSearchFieldVisible ? 0 : AndroidUtilities.dp(6));
|
||||||
backButtonFrameLayout.setLayoutParams(layoutParams1);
|
layoutParams1.topMargin = occupyStatusBar ? AndroidUtilities.statusBarHeight : 0;
|
||||||
|
titleFrameLayout.setLayoutParams(layoutParams1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void positionMenu(int width, int height) {
|
public void positionMenu(int width, int height) {
|
||||||
@ -211,52 +171,69 @@ public class ActionBarLayer extends FrameLayout {
|
|||||||
}
|
}
|
||||||
FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams)menu.getLayoutParams();
|
FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams)menu.getLayoutParams();
|
||||||
layoutParams.width = isSearchFieldVisible ? LayoutParams.MATCH_PARENT : LayoutParams.WRAP_CONTENT;
|
layoutParams.width = isSearchFieldVisible ? LayoutParams.MATCH_PARENT : LayoutParams.WRAP_CONTENT;
|
||||||
layoutParams.leftMargin = isSearchFieldVisible ? AndroidUtilities.dp(26) + logoImageView.getDrawable().getIntrinsicWidth() : 0;
|
layoutParams.height = height;
|
||||||
|
layoutParams.leftMargin = isSearchFieldVisible ? AndroidUtilities.dp(54) : 0;
|
||||||
|
layoutParams.topMargin = occupyStatusBar ? AndroidUtilities.statusBarHeight : 0;
|
||||||
menu.setLayoutParams(layoutParams);
|
menu.setLayoutParams(layoutParams);
|
||||||
menu.measure(width, height);
|
menu.measure(width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDisplayUseLogoEnabled(boolean value, int resource) {
|
private void createBackButtonImage() {
|
||||||
if (value && logoImageView == null) {
|
if (backButtonImageView != null) {
|
||||||
logoResourceId = resource;
|
return;
|
||||||
logoImageView = new ImageView(getContext());
|
|
||||||
logoImageView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
|
|
||||||
backButtonFrameLayout.addView(logoImageView);
|
|
||||||
}
|
|
||||||
if (logoImageView != null) {
|
|
||||||
logoImageView.setVisibility(value ? VISIBLE : GONE);
|
|
||||||
logoImageView.setImageResource(resource);
|
|
||||||
positionLogoImage(getMeasuredHeight());
|
|
||||||
}
|
}
|
||||||
|
backButtonImageView = new ImageView(getContext());
|
||||||
|
titleFrameLayout.addView(backButtonImageView);
|
||||||
|
backButtonImageView.setScaleType(ImageView.ScaleType.CENTER);
|
||||||
|
backButtonImageView.setBackgroundResource(itemsBackgroundResourceId);
|
||||||
|
backButtonImageView.setOnClickListener(new OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
if (isSearchFieldVisible) {
|
||||||
|
closeSearchField();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (actionBarMenuOnItemClick != null) {
|
||||||
|
actionBarMenuOnItemClick.onItemClick(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDisplayHomeAsUpEnabled(boolean value, int resource) {
|
public void setBackButtonDrawable(Drawable drawable) {
|
||||||
if (value && backButtonImageView == null) {
|
if (backButtonImageView == null) {
|
||||||
backResourceId = resource;
|
createBackButtonImage();
|
||||||
backButtonImageView = new ImageView(getContext());
|
|
||||||
backButtonFrameLayout.addView(backButtonImageView);
|
|
||||||
}
|
}
|
||||||
if (backButtonImageView != null) {
|
backButtonImageView.setImageDrawable(drawable);
|
||||||
backButtonImageView.setVisibility(value ? VISIBLE : GONE);
|
}
|
||||||
backButtonFrameLayout.setEnabled(value);
|
|
||||||
backButtonImageView.setImageResource(resource);
|
public void setBackButtonImage(int resource) {
|
||||||
positionBackImage(getMeasuredHeight());
|
if (backButtonImageView == null) {
|
||||||
|
createBackButtonImage();
|
||||||
}
|
}
|
||||||
|
backButtonImageView.setImageResource(resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createSubtitleTextView() {
|
||||||
|
if (subTitleTextView != null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
subTitleTextView = new TextView(getContext());
|
||||||
|
titleFrameLayout.addView(subTitleTextView);
|
||||||
|
subTitleTextView.setGravity(Gravity.LEFT);
|
||||||
|
subTitleTextView.setTextColor(0xffd7e8f7);
|
||||||
|
subTitleTextView.setSingleLine(true);
|
||||||
|
subTitleTextView.setLines(1);
|
||||||
|
subTitleTextView.setMaxLines(1);
|
||||||
|
subTitleTextView.setEllipsize(TextUtils.TruncateAt.END);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSubtitle(CharSequence value) {
|
public void setSubtitle(CharSequence value) {
|
||||||
if (value != null && subTitleTextView == null) {
|
if (value != null && subTitleTextView == null) {
|
||||||
subTitleTextView = new TextView(getContext());
|
createSubtitleTextView();
|
||||||
backButtonFrameLayout.addView(subTitleTextView);
|
|
||||||
subTitleTextView.setGravity(Gravity.LEFT);
|
|
||||||
subTitleTextView.setTextColor(0xffd7e8f7);
|
|
||||||
subTitleTextView.setSingleLine(true);
|
|
||||||
subTitleTextView.setLines(1);
|
|
||||||
subTitleTextView.setMaxLines(1);
|
|
||||||
subTitleTextView.setEllipsize(TextUtils.TruncateAt.END);
|
|
||||||
}
|
}
|
||||||
if (subTitleTextView != null) {
|
if (subTitleTextView != null) {
|
||||||
subTitleTextView.setVisibility(value != null ? VISIBLE : GONE);
|
subTitleTextView.setVisibility(value != null && !isSearchFieldVisible ? VISIBLE : GONE);
|
||||||
subTitleTextView.setText(value);
|
subTitleTextView.setText(value);
|
||||||
positionTitle(getMeasuredWidth(), getMeasuredHeight());
|
positionTitle(getMeasuredWidth(), getMeasuredHeight());
|
||||||
}
|
}
|
||||||
@ -264,14 +241,7 @@ public class ActionBarLayer extends FrameLayout {
|
|||||||
|
|
||||||
public void setSubTitleIcon(int resourceId, Drawable drawable, int padding) {
|
public void setSubTitleIcon(int resourceId, Drawable drawable, int padding) {
|
||||||
if ((resourceId != 0 || drawable != null) && subTitleTextView == null) {
|
if ((resourceId != 0 || drawable != null) && subTitleTextView == null) {
|
||||||
subTitleTextView = new TextView(getContext());
|
createSubtitleTextView();
|
||||||
backButtonFrameLayout.addView(subTitleTextView);
|
|
||||||
subTitleTextView.setGravity(Gravity.LEFT);
|
|
||||||
subTitleTextView.setTextColor(0xffd7e8f7);
|
|
||||||
subTitleTextView.setSingleLine(true);
|
|
||||||
subTitleTextView.setLines(1);
|
|
||||||
subTitleTextView.setMaxLines(1);
|
|
||||||
subTitleTextView.setEllipsize(TextUtils.TruncateAt.END);
|
|
||||||
positionTitle(getMeasuredWidth(), getMeasuredHeight());
|
positionTitle(getMeasuredWidth(), getMeasuredHeight());
|
||||||
}
|
}
|
||||||
if (subTitleTextView != null) {
|
if (subTitleTextView != null) {
|
||||||
@ -284,19 +254,28 @@ public class ActionBarLayer extends FrameLayout {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void createTitleTextView() {
|
||||||
|
if (titleTextView != null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
titleTextView = new TextView(getContext());
|
||||||
|
titleTextView.setGravity(Gravity.LEFT);
|
||||||
|
titleTextView.setSingleLine(true);
|
||||||
|
titleTextView.setLines(1);
|
||||||
|
titleTextView.setMaxLines(1);
|
||||||
|
titleTextView.setEllipsize(TextUtils.TruncateAt.END);
|
||||||
|
titleFrameLayout.addView(titleTextView);
|
||||||
|
titleTextView.setTextColor(0xffffffff);
|
||||||
|
titleTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf"));
|
||||||
|
}
|
||||||
|
|
||||||
public void setTitle(CharSequence value) {
|
public void setTitle(CharSequence value) {
|
||||||
if (value != null && titleTextView == null) {
|
if (value != null && titleTextView == null) {
|
||||||
titleTextView = new TextView(getContext());
|
createTitleTextView();
|
||||||
titleTextView.setGravity(Gravity.LEFT);
|
|
||||||
titleTextView.setSingleLine(true);
|
|
||||||
titleTextView.setLines(1);
|
|
||||||
titleTextView.setMaxLines(1);
|
|
||||||
titleTextView.setEllipsize(TextUtils.TruncateAt.END);
|
|
||||||
backButtonFrameLayout.addView(titleTextView);
|
|
||||||
titleTextView.setTextColor(0xffffffff);
|
|
||||||
}
|
}
|
||||||
if (titleTextView != null) {
|
if (titleTextView != null) {
|
||||||
titleTextView.setVisibility(value != null ? VISIBLE : GONE);
|
lastTitle = value;
|
||||||
|
titleTextView.setVisibility(value != null && !isSearchFieldVisible ? VISIBLE : GONE);
|
||||||
titleTextView.setText(value);
|
titleTextView.setText(value);
|
||||||
positionTitle(getMeasuredWidth(), getMeasuredHeight());
|
positionTitle(getMeasuredWidth(), getMeasuredHeight());
|
||||||
}
|
}
|
||||||
@ -304,14 +283,7 @@ public class ActionBarLayer extends FrameLayout {
|
|||||||
|
|
||||||
public void setTitleIcon(int resourceId, int padding) {
|
public void setTitleIcon(int resourceId, int padding) {
|
||||||
if (resourceId != 0 && titleTextView == null) {
|
if (resourceId != 0 && titleTextView == null) {
|
||||||
titleTextView = new TextView(getContext());
|
createTitleTextView();
|
||||||
titleTextView.setGravity(Gravity.LEFT);
|
|
||||||
backButtonFrameLayout.addView(titleTextView);
|
|
||||||
titleTextView.setTextColor(0xffffffff);
|
|
||||||
titleTextView.setSingleLine(true);
|
|
||||||
titleTextView.setLines(1);
|
|
||||||
titleTextView.setMaxLines(1);
|
|
||||||
titleTextView.setEllipsize(TextUtils.TruncateAt.END);
|
|
||||||
positionTitle(getMeasuredWidth(), getMeasuredHeight());
|
positionTitle(getMeasuredWidth(), getMeasuredHeight());
|
||||||
}
|
}
|
||||||
titleTextView.setCompoundDrawablesWithIntrinsicBounds(resourceId, 0, 0, 0);
|
titleTextView.setCompoundDrawablesWithIntrinsicBounds(resourceId, 0, 0, 0);
|
||||||
@ -333,7 +305,7 @@ public class ActionBarLayer extends FrameLayout {
|
|||||||
if (menu != null) {
|
if (menu != null) {
|
||||||
return menu;
|
return menu;
|
||||||
}
|
}
|
||||||
menu = new ActionBarMenu(getContext(), parentActionBar, this);
|
menu = new ActionBarMenu(getContext(), this);
|
||||||
addView(menu);
|
addView(menu);
|
||||||
FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams)menu.getLayoutParams();
|
FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams)menu.getLayoutParams();
|
||||||
layoutParams.height = LayoutParams.FILL_PARENT;
|
layoutParams.height = LayoutParams.FILL_PARENT;
|
||||||
@ -343,10 +315,6 @@ public class ActionBarLayer extends FrameLayout {
|
|||||||
return menu;
|
return menu;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onDestroy() {
|
|
||||||
parentActionBar.detachActionBarLayer(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setActionBarMenuOnItemClick(ActionBarMenuOnItemClick listener) {
|
public void setActionBarMenuOnItemClick(ActionBarMenuOnItemClick listener) {
|
||||||
actionBarMenuOnItemClick = listener;
|
actionBarMenuOnItemClick = listener;
|
||||||
}
|
}
|
||||||
@ -355,21 +323,40 @@ public class ActionBarLayer extends FrameLayout {
|
|||||||
LayoutInflater li = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
LayoutInflater li = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||||
View view = li.inflate(resourceId, null);
|
View view = li.inflate(resourceId, null);
|
||||||
addView(view);
|
addView(view);
|
||||||
|
FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams)view.getLayoutParams();
|
||||||
|
layoutParams.width = LayoutParams.FILL_PARENT;
|
||||||
|
layoutParams.height = LayoutParams.FILL_PARENT;
|
||||||
|
layoutParams.topMargin = occupyStatusBar ? AndroidUtilities.statusBarHeight : 0;
|
||||||
|
view.setLayoutParams(layoutParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ActionBarMenu createActionMode() {
|
public ActionBarMenu createActionMode() {
|
||||||
if (actionMode != null) {
|
if (actionMode != null) {
|
||||||
return actionMode;
|
return actionMode;
|
||||||
}
|
}
|
||||||
actionMode = new ActionBarMenu(getContext(), parentActionBar, this);
|
actionMode = new ActionBarMenu(getContext(), this);
|
||||||
actionMode.setBackgroundResource(R.drawable.editheader);
|
actionMode.setBackgroundResource(R.drawable.editheader);
|
||||||
addView(actionMode);
|
addView(actionMode);
|
||||||
|
actionMode.setPadding(0, occupyStatusBar ? AndroidUtilities.statusBarHeight : 0, 0, 0);
|
||||||
FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams)actionMode.getLayoutParams();
|
FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams)actionMode.getLayoutParams();
|
||||||
layoutParams.height = LayoutParams.FILL_PARENT;
|
layoutParams.height = LayoutParams.FILL_PARENT;
|
||||||
layoutParams.width = LayoutParams.FILL_PARENT;
|
layoutParams.width = LayoutParams.FILL_PARENT;
|
||||||
layoutParams.gravity = Gravity.RIGHT;
|
layoutParams.gravity = Gravity.RIGHT;
|
||||||
actionMode.setLayoutParams(layoutParams);
|
actionMode.setLayoutParams(layoutParams);
|
||||||
actionMode.setVisibility(GONE);
|
actionMode.setVisibility(GONE);
|
||||||
|
|
||||||
|
if (occupyStatusBar) {
|
||||||
|
actionModeTop = new View(getContext());
|
||||||
|
actionModeTop.setBackgroundColor(0x99000000);
|
||||||
|
addView(actionModeTop);
|
||||||
|
layoutParams = (FrameLayout.LayoutParams)actionModeTop.getLayoutParams();
|
||||||
|
layoutParams.height = AndroidUtilities.statusBarHeight;
|
||||||
|
layoutParams.width = LayoutParams.FILL_PARENT;
|
||||||
|
layoutParams.gravity = Gravity.TOP | Gravity.LEFT;
|
||||||
|
actionModeTop.setLayoutParams(layoutParams);
|
||||||
|
actionModeTop.setVisibility(GONE);
|
||||||
|
}
|
||||||
|
|
||||||
return actionMode;
|
return actionMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -378,8 +365,11 @@ public class ActionBarLayer extends FrameLayout {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
actionMode.setVisibility(VISIBLE);
|
actionMode.setVisibility(VISIBLE);
|
||||||
if (backButtonFrameLayout != null) {
|
if (actionModeTop != null) {
|
||||||
backButtonFrameLayout.setVisibility(INVISIBLE);
|
actionModeTop.setVisibility(VISIBLE);
|
||||||
|
}
|
||||||
|
if (titleFrameLayout != null) {
|
||||||
|
titleFrameLayout.setVisibility(INVISIBLE);
|
||||||
}
|
}
|
||||||
if (menu != null) {
|
if (menu != null) {
|
||||||
menu.setVisibility(INVISIBLE);
|
menu.setVisibility(INVISIBLE);
|
||||||
@ -391,8 +381,11 @@ public class ActionBarLayer extends FrameLayout {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
actionMode.setVisibility(GONE);
|
actionMode.setVisibility(GONE);
|
||||||
if (backButtonFrameLayout != null) {
|
if (actionModeTop != null) {
|
||||||
backButtonFrameLayout.setVisibility(isSearchFieldVisible || actionOverlay == null || actionOverlay.getVisibility() == GONE ? VISIBLE : INVISIBLE);
|
actionModeTop.setVisibility(GONE);
|
||||||
|
}
|
||||||
|
if (titleFrameLayout != null) {
|
||||||
|
titleFrameLayout.setVisibility(VISIBLE);
|
||||||
}
|
}
|
||||||
if (menu != null) {
|
if (menu != null) {
|
||||||
menu.setVisibility(VISIBLE);
|
menu.setVisibility(VISIBLE);
|
||||||
@ -411,20 +404,10 @@ public class ActionBarLayer extends FrameLayout {
|
|||||||
if (subTitleTextView != null) {
|
if (subTitleTextView != null) {
|
||||||
subTitleTextView.setVisibility(visible ? GONE : VISIBLE);
|
subTitleTextView.setVisibility(visible ? GONE : VISIBLE);
|
||||||
}
|
}
|
||||||
backButtonFrameLayout.setPadding(0, 0, visible ? 0 : AndroidUtilities.dp(4), 0);
|
Drawable drawable = backButtonImageView.getDrawable();
|
||||||
if (visible) {
|
if (drawable != null && drawable instanceof MenuDrawable) {
|
||||||
oldUseLogo = logoImageView != null && logoImageView.getVisibility() == VISIBLE;
|
((MenuDrawable)drawable).setRotation(visible ? 1 : 0, true);
|
||||||
setDisplayUseLogoEnabled(true, R.drawable.ic_ab_search);
|
|
||||||
} else {
|
|
||||||
setDisplayUseLogoEnabled(oldUseLogo, logoResourceId);
|
|
||||||
}
|
}
|
||||||
if (visible) {
|
|
||||||
oldUseBack = backButtonImageView != null && backButtonImageView.getVisibility() == VISIBLE;
|
|
||||||
setDisplayHomeAsUpEnabled(true, R.drawable.ic_ab_back);
|
|
||||||
} else {
|
|
||||||
setDisplayHomeAsUpEnabled(oldUseBack, backResourceId);
|
|
||||||
}
|
|
||||||
positionBackOverlay(getMeasuredWidth(), getMeasuredHeight());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void closeSearchField() {
|
public void closeSearchField() {
|
||||||
@ -436,22 +419,12 @@ public class ActionBarLayer extends FrameLayout {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||||
positionLogoImage(MeasureSpec.getSize(heightMeasureSpec));
|
int actionBarHeight = AndroidUtilities.getCurrentActionBarHeight();
|
||||||
positionBackImage(MeasureSpec.getSize(heightMeasureSpec));
|
positionBackImage(actionBarHeight);
|
||||||
positionMenu(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.getSize(heightMeasureSpec));
|
positionMenu(MeasureSpec.getSize(widthMeasureSpec), actionBarHeight);
|
||||||
positionTitle(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.getSize(heightMeasureSpec));
|
positionTitle(MeasureSpec.getSize(widthMeasureSpec), actionBarHeight);
|
||||||
positionBackOverlay(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.getSize(heightMeasureSpec));
|
actionBarHeight += occupyStatusBar ? AndroidUtilities.statusBarHeight : 0;
|
||||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(actionBarHeight + extraHeight, MeasureSpec.EXACTLY));
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setAlpha(float alpha) {
|
|
||||||
if (menu != null) {
|
|
||||||
menu.setAlpha(alpha);
|
|
||||||
}
|
|
||||||
if (backButtonFrameLayout != null) {
|
|
||||||
backButtonFrameLayout.setAlpha(alpha);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onMenuButtonPressed() {
|
public void onMenuButtonPressed() {
|
||||||
@ -466,51 +439,55 @@ public class ActionBarLayer extends FrameLayout {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setBackOverlay(int resourceId) {
|
public void setAllowOverlayTitle(boolean value) {
|
||||||
LayoutInflater li = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
allowOverlayTitle = value;
|
||||||
actionOverlay = li.inflate(resourceId, null);
|
|
||||||
addView(actionOverlay);
|
|
||||||
actionOverlay.setVisibility(GONE);
|
|
||||||
actionOverlay.setOnClickListener(new OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
if (actionBarMenuOnItemClick != null) {
|
|
||||||
actionBarMenuOnItemClick.onItemClick(-1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setBackOverlayVisible(boolean visible) {
|
public void setTitleOverlayText(String text) {
|
||||||
if (actionOverlay == null || parentFragment == null || parentFragment.parentLayout == null) {
|
if (showingOverlayTitle == (text != null) || !allowOverlayTitle || parentFragment.parentLayout == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
isBackOverlayVisible = visible;
|
showingOverlayTitle = text != null;
|
||||||
if (visible) {
|
CharSequence textToSet = text != null ? text : lastTitle;
|
||||||
parentFragment.parentLayout.onOverlayShow(actionOverlay, parentFragment);
|
if (textToSet != null && titleTextView == null) {
|
||||||
|
createTitleTextView();
|
||||||
|
}
|
||||||
|
if (titleTextView != null) {
|
||||||
|
titleTextView.setVisibility(textToSet != null && !isSearchFieldVisible ? VISIBLE : GONE);
|
||||||
|
titleTextView.setText(textToSet);
|
||||||
|
positionTitle(getMeasuredWidth(), getMeasuredHeight());
|
||||||
}
|
}
|
||||||
positionBackOverlay(getMeasuredWidth(), getMeasuredHeight());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void positionBackOverlay(int widthMeasureSpec, int heightMeasureSpec) {
|
public void setExtraHeight(int value, boolean layout) {
|
||||||
if (actionOverlay == null) {
|
extraHeight = value;
|
||||||
return;
|
if (layout) {
|
||||||
}
|
requestLayout();
|
||||||
backButtonFrameLayout.setVisibility(isSearchFieldVisible || actionOverlay == null || actionOverlay.getVisibility() == GONE ? VISIBLE : INVISIBLE);
|
|
||||||
actionOverlay.setVisibility(!isSearchFieldVisible && isBackOverlayVisible ? VISIBLE : GONE);
|
|
||||||
if (actionOverlay.getVisibility() == VISIBLE) {
|
|
||||||
ViewGroup.LayoutParams layoutParams = actionOverlay.getLayoutParams();
|
|
||||||
layoutParams.width = LayoutParams.WRAP_CONTENT;
|
|
||||||
layoutParams.height = LayoutParams.MATCH_PARENT;
|
|
||||||
actionOverlay.setLayoutParams(layoutParams);
|
|
||||||
actionOverlay.measure(widthMeasureSpec, heightMeasureSpec);
|
|
||||||
layoutParams.width = Math.min(actionOverlay.getMeasuredWidth() + AndroidUtilities.dp(4), widthMeasureSpec - (menu != null ? menu.getMeasuredWidth() : 0));
|
|
||||||
actionOverlay.setLayoutParams(layoutParams);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getExtraHeight() {
|
||||||
|
return extraHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOccupyStatusBar(boolean value) {
|
||||||
|
occupyStatusBar = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getOccupyStatusBar() {
|
||||||
|
return occupyStatusBar;
|
||||||
|
}
|
||||||
|
|
||||||
public void setItemsBackground(int resourceId) {
|
public void setItemsBackground(int resourceId) {
|
||||||
itemsBackgroundResourceId = resourceId;
|
itemsBackgroundResourceId = resourceId;
|
||||||
backButtonFrameLayout.setBackgroundResource(itemsBackgroundResourceId);
|
if (backButtonImageView != null) {
|
||||||
|
backButtonImageView.setBackgroundResource(itemsBackgroundResourceId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onTouchEvent(MotionEvent event) {
|
||||||
|
super.onTouchEvent(event);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,963 @@
|
|||||||
|
/*
|
||||||
|
* This is the source code of Telegram for Android v. 1.4.x.
|
||||||
|
* It is licensed under GNU GPL v. 2 or later.
|
||||||
|
* You should have received a copy of the license in this archive (see LICENSE).
|
||||||
|
*
|
||||||
|
* Copyright Nikolai Kudashov, 2013-2014.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.telegram.ui.ActionBar;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.view.ActionMode;
|
||||||
|
import android.view.Gravity;
|
||||||
|
import android.view.KeyEvent;
|
||||||
|
import android.view.MotionEvent;
|
||||||
|
import android.view.VelocityTracker;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.view.animation.AccelerateDecelerateInterpolator;
|
||||||
|
import android.view.animation.DecelerateInterpolator;
|
||||||
|
import android.widget.FrameLayout;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
|
||||||
|
import org.telegram.android.AndroidUtilities;
|
||||||
|
import org.telegram.android.NotificationCenter;
|
||||||
|
import org.telegram.messenger.R;
|
||||||
|
import org.telegram.ui.AnimationCompat.AnimatorListenerAdapterProxy;
|
||||||
|
import org.telegram.ui.AnimationCompat.AnimatorSetProxy;
|
||||||
|
import org.telegram.ui.AnimationCompat.ObjectAnimatorProxy;
|
||||||
|
import org.telegram.ui.AnimationCompat.ViewProxy;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class ActionBarLayout extends FrameLayout {
|
||||||
|
|
||||||
|
public static interface ActionBarLayoutDelegate {
|
||||||
|
public abstract boolean onPreIme();
|
||||||
|
public abstract boolean needPresentFragment(BaseFragment fragment, boolean removeLast, boolean forceWithoutAnimation, ActionBarLayout layout);
|
||||||
|
public abstract boolean needAddFragmentToStack(BaseFragment fragment, ActionBarLayout layout);
|
||||||
|
public abstract boolean needCloseLastFragment(ActionBarLayout layout);
|
||||||
|
public abstract void onRebuildAllFragments(ActionBarLayout layout);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class LinearLayoutContainer extends LinearLayout {
|
||||||
|
|
||||||
|
public LinearLayoutContainer(Context context) {
|
||||||
|
super(context);
|
||||||
|
setOrientation(VERTICAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
|
||||||
|
if (child instanceof ActionBar) {
|
||||||
|
return super.drawChild(canvas, child, drawingTime);
|
||||||
|
} else {
|
||||||
|
boolean wasActionBar = false;
|
||||||
|
int actionBarHeight = 0;
|
||||||
|
int childCount = getChildCount();
|
||||||
|
for (int a = 0; a < childCount; a++) {
|
||||||
|
View view = getChildAt(a);
|
||||||
|
if (view == child) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (view instanceof ActionBar && view.getVisibility() == VISIBLE) {
|
||||||
|
actionBarHeight = view.getMeasuredHeight();
|
||||||
|
wasActionBar = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*if (!wasActionBar) {
|
||||||
|
if (child instanceof ViewGroup) {
|
||||||
|
ViewGroup viewGroup = (ViewGroup) child;
|
||||||
|
childCount = viewGroup.getChildCount();
|
||||||
|
for (int a = 0; a < childCount; a++) {
|
||||||
|
View possibleActionBar = viewGroup.getChildAt(a);
|
||||||
|
if (possibleActionBar instanceof ActionBar) {
|
||||||
|
actionBarHeight = possibleActionBar.getMeasuredHeight();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
boolean result = super.drawChild(canvas, child, drawingTime);
|
||||||
|
if (actionBarHeight != 0 && headerShadowDrawable != null) {
|
||||||
|
headerShadowDrawable.setBounds(0, actionBarHeight, getMeasuredWidth(), actionBarHeight + headerShadowDrawable.getIntrinsicHeight());
|
||||||
|
headerShadowDrawable.draw(canvas);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Drawable headerShadowDrawable;
|
||||||
|
private static Drawable layerShadowDrawable;
|
||||||
|
private static Paint scrimPaint;
|
||||||
|
|
||||||
|
private LinearLayoutContainer containerView;
|
||||||
|
private LinearLayoutContainer containerViewBack;
|
||||||
|
private DrawerLayoutContainer drawerLayoutContainer;
|
||||||
|
private ActionBar currentActionBar;
|
||||||
|
|
||||||
|
private AnimatorSetProxy currentAnimation;
|
||||||
|
|
||||||
|
public float innerTranslationX;
|
||||||
|
|
||||||
|
private boolean maybeStartTracking;
|
||||||
|
protected boolean startedTracking;
|
||||||
|
private int startedTrackingX;
|
||||||
|
private int startedTrackingY;
|
||||||
|
protected boolean animationInProgress;
|
||||||
|
private VelocityTracker velocityTracker;
|
||||||
|
private boolean beginTrackingSent;
|
||||||
|
private boolean transitionAnimationInProgress;
|
||||||
|
private long transitionAnimationStartTime;
|
||||||
|
private boolean inActionMode;
|
||||||
|
private int startedTrackingPointerId;
|
||||||
|
private Runnable onCloseAnimationEndRunnable;
|
||||||
|
private Runnable onOpenAnimationEndRunnable;
|
||||||
|
private boolean useAlphaAnimations;
|
||||||
|
private View backgroundView;
|
||||||
|
private boolean removeActionBarExtraHeight;
|
||||||
|
|
||||||
|
private String titleOverlayText;
|
||||||
|
|
||||||
|
private ActionBarLayoutDelegate delegate = null;
|
||||||
|
protected Activity parentActivity = null;
|
||||||
|
|
||||||
|
public ArrayList<BaseFragment> fragmentsStack = null;
|
||||||
|
|
||||||
|
public ActionBarLayout(Context context) {
|
||||||
|
super(context);
|
||||||
|
parentActivity = (Activity) context;
|
||||||
|
|
||||||
|
if (layerShadowDrawable == null) {
|
||||||
|
layerShadowDrawable = getResources().getDrawable(R.drawable.layer_shadow);
|
||||||
|
headerShadowDrawable = getResources().getDrawable(R.drawable.header_shadow);
|
||||||
|
scrimPaint = new Paint();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void init(ArrayList<BaseFragment> stack) {
|
||||||
|
fragmentsStack = stack;
|
||||||
|
containerViewBack = new LinearLayoutContainer(parentActivity);
|
||||||
|
addView(containerViewBack);
|
||||||
|
FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) containerViewBack.getLayoutParams();
|
||||||
|
layoutParams.width = LayoutParams.MATCH_PARENT;
|
||||||
|
layoutParams.height = LayoutParams.MATCH_PARENT;
|
||||||
|
layoutParams.gravity = Gravity.TOP | Gravity.LEFT;
|
||||||
|
containerViewBack.setLayoutParams(layoutParams);
|
||||||
|
|
||||||
|
containerView = new LinearLayoutContainer(parentActivity);
|
||||||
|
addView(containerView);
|
||||||
|
layoutParams = (FrameLayout.LayoutParams) containerView.getLayoutParams();
|
||||||
|
layoutParams.width = LayoutParams.MATCH_PARENT;
|
||||||
|
layoutParams.height = LayoutParams.MATCH_PARENT;
|
||||||
|
layoutParams.gravity = Gravity.TOP | Gravity.LEFT;
|
||||||
|
containerView.setLayoutParams(layoutParams);
|
||||||
|
|
||||||
|
for (BaseFragment fragment : fragmentsStack) {
|
||||||
|
fragment.setParentLayout(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onConfigurationChanged(android.content.res.Configuration newConfig) {
|
||||||
|
super.onConfigurationChanged(newConfig);
|
||||||
|
if (!fragmentsStack.isEmpty()) {
|
||||||
|
BaseFragment lastFragment = fragmentsStack.get(fragmentsStack.size() - 1);
|
||||||
|
lastFragment.onConfigurationChanged(newConfig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInnerTranslationX(float value) {
|
||||||
|
innerTranslationX = value;
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getInnerTranslationX() {
|
||||||
|
return innerTranslationX;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onResume() {
|
||||||
|
if (transitionAnimationInProgress) {
|
||||||
|
if (currentAnimation != null) {
|
||||||
|
currentAnimation.cancel();
|
||||||
|
currentAnimation = null;
|
||||||
|
}
|
||||||
|
if (onCloseAnimationEndRunnable != null) {
|
||||||
|
onCloseAnimationEnd(false);
|
||||||
|
} else if (onOpenAnimationEndRunnable != null) {
|
||||||
|
onOpenAnimationEnd(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!fragmentsStack.isEmpty()) {
|
||||||
|
BaseFragment lastFragment = fragmentsStack.get(fragmentsStack.size() - 1);
|
||||||
|
lastFragment.onResume();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onPause() {
|
||||||
|
if (!fragmentsStack.isEmpty()) {
|
||||||
|
BaseFragment lastFragment = fragmentsStack.get(fragmentsStack.size() - 1);
|
||||||
|
lastFragment.onPause();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onInterceptTouchEvent(MotionEvent ev) {
|
||||||
|
return !(!animationInProgress && !checkTransitionAnimation()) || onTouchEvent(ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
|
||||||
|
onTouchEvent(null);
|
||||||
|
super.requestDisallowInterceptTouchEvent(disallowIntercept);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean dispatchKeyEventPreIme(KeyEvent event) {
|
||||||
|
if (event != null && event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
|
||||||
|
return delegate != null && delegate.onPreIme() || super.dispatchKeyEventPreIme(event);
|
||||||
|
}
|
||||||
|
return super.dispatchKeyEventPreIme(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
|
||||||
|
int width = getWidth() - getPaddingLeft() - getPaddingRight();
|
||||||
|
int translationX = (int) innerTranslationX + getPaddingRight();
|
||||||
|
int clipLeft = getPaddingLeft();
|
||||||
|
int clipRight = width + getPaddingLeft();
|
||||||
|
|
||||||
|
if (child == containerViewBack) {
|
||||||
|
clipRight = translationX;
|
||||||
|
} else if (child == containerView) {
|
||||||
|
clipLeft = translationX;
|
||||||
|
}
|
||||||
|
|
||||||
|
final int restoreCount = canvas.save();
|
||||||
|
if (!transitionAnimationInProgress) {
|
||||||
|
canvas.clipRect(clipLeft, 0, clipRight, getHeight());
|
||||||
|
}
|
||||||
|
final boolean result = super.drawChild(canvas, child, drawingTime);
|
||||||
|
canvas.restoreToCount(restoreCount);
|
||||||
|
|
||||||
|
if (translationX != 0) {
|
||||||
|
if (child == containerView) {
|
||||||
|
final float alpha = Math.max(0, Math.min((width - translationX) / (float) AndroidUtilities.dp(20), 1.0f));
|
||||||
|
layerShadowDrawable.setBounds(translationX - layerShadowDrawable.getIntrinsicWidth(), child.getTop(), translationX, child.getBottom());
|
||||||
|
layerShadowDrawable.setAlpha((int) (0xff * alpha));
|
||||||
|
layerShadowDrawable.draw(canvas);
|
||||||
|
} else if (child == containerViewBack) {
|
||||||
|
final float opacity = Math.min(0.8f, (width - translationX) / (float)width);
|
||||||
|
scrimPaint.setColor((int) (((0x99000000 & 0xff000000) >>> 24) * opacity) << 24);
|
||||||
|
canvas.drawRect(clipLeft, 0, clipRight, getHeight(), scrimPaint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDelegate(ActionBarLayoutDelegate delegate) {
|
||||||
|
this.delegate = delegate;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onSlideAnimationEnd(final boolean backAnimation) {
|
||||||
|
if (!backAnimation) {
|
||||||
|
BaseFragment lastFragment = fragmentsStack.get(fragmentsStack.size() - 1);
|
||||||
|
lastFragment.onPause();
|
||||||
|
lastFragment.onFragmentDestroy();
|
||||||
|
lastFragment.setParentLayout(null);
|
||||||
|
fragmentsStack.remove(fragmentsStack.size() - 1);
|
||||||
|
|
||||||
|
LinearLayoutContainer temp = containerView;
|
||||||
|
containerView = containerViewBack;
|
||||||
|
containerViewBack = temp;
|
||||||
|
bringChildToFront(containerView);
|
||||||
|
|
||||||
|
lastFragment = fragmentsStack.get(fragmentsStack.size() - 1);
|
||||||
|
currentActionBar = lastFragment.actionBar;
|
||||||
|
lastFragment.onResume();
|
||||||
|
} else {
|
||||||
|
BaseFragment lastFragment = fragmentsStack.get(fragmentsStack.size() - 2);
|
||||||
|
lastFragment.onPause();
|
||||||
|
if (lastFragment.fragmentView != null) {
|
||||||
|
ViewGroup parent = (ViewGroup) lastFragment.fragmentView.getParent();
|
||||||
|
if (parent != null) {
|
||||||
|
parent.removeView(lastFragment.fragmentView);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (lastFragment.needAddActionBar() && lastFragment.actionBar != null) {
|
||||||
|
ViewGroup parent = (ViewGroup) lastFragment.actionBar.getParent();
|
||||||
|
if (parent != null) {
|
||||||
|
parent.removeView(lastFragment.actionBar);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
containerViewBack.setVisibility(View.GONE);
|
||||||
|
//AndroidUtilities.unlockOrientation(parentActivity);
|
||||||
|
startedTracking = false;
|
||||||
|
animationInProgress = false;
|
||||||
|
|
||||||
|
ViewProxy.setTranslationX(containerView, 0);
|
||||||
|
ViewProxy.setTranslationX(containerViewBack, 0);
|
||||||
|
setInnerTranslationX(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void prepareForMoving(MotionEvent ev) {
|
||||||
|
maybeStartTracking = false;
|
||||||
|
startedTracking = true;
|
||||||
|
startedTrackingX = (int) ev.getX();
|
||||||
|
containerViewBack.setVisibility(View.VISIBLE);
|
||||||
|
beginTrackingSent = false;
|
||||||
|
|
||||||
|
BaseFragment lastFragment = fragmentsStack.get(fragmentsStack.size() - 2);
|
||||||
|
View fragmentView = lastFragment.createView(parentActivity.getLayoutInflater(), null);
|
||||||
|
ViewGroup parent = (ViewGroup) fragmentView.getParent();
|
||||||
|
if (parent != null) {
|
||||||
|
parent.removeView(fragmentView);
|
||||||
|
}
|
||||||
|
if (lastFragment.needAddActionBar() && lastFragment.actionBar != null) {
|
||||||
|
parent = (ViewGroup) lastFragment.actionBar.getParent();
|
||||||
|
if (parent != null) {
|
||||||
|
parent.removeView(lastFragment.actionBar);
|
||||||
|
}
|
||||||
|
if (removeActionBarExtraHeight) {
|
||||||
|
lastFragment.actionBar.setOccupyStatusBar(false);
|
||||||
|
}
|
||||||
|
containerViewBack.addView(lastFragment.actionBar);
|
||||||
|
lastFragment.actionBar.setTitleOverlayText(titleOverlayText);
|
||||||
|
}
|
||||||
|
containerViewBack.addView(fragmentView);
|
||||||
|
ViewGroup.LayoutParams layoutParams = fragmentView.getLayoutParams();
|
||||||
|
layoutParams.width = FrameLayout.LayoutParams.MATCH_PARENT;
|
||||||
|
layoutParams.height = FrameLayout.LayoutParams.MATCH_PARENT;
|
||||||
|
fragmentView.setLayoutParams(layoutParams);
|
||||||
|
if (fragmentView.getBackground() == null) {
|
||||||
|
fragmentView.setBackgroundColor(0xffffffff);
|
||||||
|
}
|
||||||
|
lastFragment.onResume();
|
||||||
|
|
||||||
|
//AndroidUtilities.lockOrientation(parentActivity);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean onTouchEvent(MotionEvent ev) {
|
||||||
|
if (!checkTransitionAnimation() && !inActionMode && !animationInProgress) {
|
||||||
|
if (fragmentsStack.size() > 1) {
|
||||||
|
if (ev != null && ev.getAction() == MotionEvent.ACTION_DOWN && !startedTracking && !maybeStartTracking) {
|
||||||
|
BaseFragment currentFragment = fragmentsStack.get(fragmentsStack.size() - 1);
|
||||||
|
if (!currentFragment.swipeBackEnabled) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
startedTrackingPointerId = ev.getPointerId(0);
|
||||||
|
maybeStartTracking = true;
|
||||||
|
startedTrackingX = (int) ev.getX();
|
||||||
|
startedTrackingY = (int) ev.getY();
|
||||||
|
if (velocityTracker != null) {
|
||||||
|
velocityTracker.clear();
|
||||||
|
}
|
||||||
|
} else if (ev != null && ev.getAction() == MotionEvent.ACTION_MOVE && ev.getPointerId(0) == startedTrackingPointerId) {
|
||||||
|
if (velocityTracker == null) {
|
||||||
|
velocityTracker = VelocityTracker.obtain();
|
||||||
|
}
|
||||||
|
int dx = Math.max(0, (int) (ev.getX() - startedTrackingX));
|
||||||
|
int dy = Math.abs((int) ev.getY() - startedTrackingY);
|
||||||
|
velocityTracker.addMovement(ev);
|
||||||
|
if (maybeStartTracking && !startedTracking && dx >= AndroidUtilities.dp(10) && Math.abs(dx) / 3 > dy) {
|
||||||
|
prepareForMoving(ev);
|
||||||
|
} else if (startedTracking) {
|
||||||
|
if (!beginTrackingSent) {
|
||||||
|
if (parentActivity.getCurrentFocus() != null) {
|
||||||
|
AndroidUtilities.hideKeyboard(parentActivity.getCurrentFocus());
|
||||||
|
}
|
||||||
|
BaseFragment currentFragment = fragmentsStack.get(fragmentsStack.size() - 1);
|
||||||
|
currentFragment.onBeginSlide();
|
||||||
|
beginTrackingSent = true;
|
||||||
|
}
|
||||||
|
ViewProxy.setTranslationX(containerView, dx);
|
||||||
|
setInnerTranslationX(dx);
|
||||||
|
}
|
||||||
|
} else if (ev != null && ev.getPointerId(0) == startedTrackingPointerId && (ev.getAction() == MotionEvent.ACTION_CANCEL || ev.getAction() == MotionEvent.ACTION_UP || ev.getAction() == MotionEvent.ACTION_POINTER_UP)) {
|
||||||
|
if (velocityTracker == null) {
|
||||||
|
velocityTracker = VelocityTracker.obtain();
|
||||||
|
}
|
||||||
|
velocityTracker.computeCurrentVelocity(1000);
|
||||||
|
if (!startedTracking) {
|
||||||
|
float velX = velocityTracker.getXVelocity();
|
||||||
|
float velY = velocityTracker.getYVelocity();
|
||||||
|
if (velX >= 3500 && velX > velY) {
|
||||||
|
prepareForMoving(ev);
|
||||||
|
if (!beginTrackingSent) {
|
||||||
|
if (((Activity) getContext()).getCurrentFocus() != null) {
|
||||||
|
AndroidUtilities.hideKeyboard(((Activity) getContext()).getCurrentFocus());
|
||||||
|
}
|
||||||
|
beginTrackingSent = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (startedTracking) {
|
||||||
|
float x = ViewProxy.getX(containerView);
|
||||||
|
AnimatorSetProxy animatorSet = new AnimatorSetProxy();
|
||||||
|
float velX = velocityTracker.getXVelocity();
|
||||||
|
float velY = velocityTracker.getYVelocity();
|
||||||
|
final boolean backAnimation = x < containerView.getMeasuredWidth() / 3.0f && (velX < 3500 || velX < velY);
|
||||||
|
float distToMove = 0;
|
||||||
|
if (!backAnimation) {
|
||||||
|
distToMove = containerView.getMeasuredWidth() - x;
|
||||||
|
animatorSet.playTogether(
|
||||||
|
ObjectAnimatorProxy.ofFloat(containerView, "x", containerView.getMeasuredWidth()),
|
||||||
|
ObjectAnimatorProxy.ofFloat(this, "innerTranslationX", (float)containerView.getMeasuredWidth())
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
distToMove = x;
|
||||||
|
animatorSet.playTogether(
|
||||||
|
ObjectAnimatorProxy.ofFloat(containerView, "x", 0),
|
||||||
|
ObjectAnimatorProxy.ofFloat(this, "innerTranslationX", 0.0f)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
animatorSet.setDuration(Math.max((int) (200.0f / containerView.getMeasuredWidth() * distToMove), 50));
|
||||||
|
animatorSet.addListener(new AnimatorListenerAdapterProxy() {
|
||||||
|
@Override
|
||||||
|
public void onAnimationEnd(Object animator) {
|
||||||
|
onSlideAnimationEnd(backAnimation);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAnimationCancel(Object animator) {
|
||||||
|
onSlideAnimationEnd(backAnimation);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
animatorSet.start();
|
||||||
|
animationInProgress = true;
|
||||||
|
} else {
|
||||||
|
maybeStartTracking = false;
|
||||||
|
startedTracking = false;
|
||||||
|
}
|
||||||
|
if (velocityTracker != null) {
|
||||||
|
velocityTracker.recycle();
|
||||||
|
velocityTracker = null;
|
||||||
|
}
|
||||||
|
} else if (ev == null) {
|
||||||
|
maybeStartTracking = false;
|
||||||
|
startedTracking = false;
|
||||||
|
if (velocityTracker != null) {
|
||||||
|
velocityTracker.recycle();
|
||||||
|
velocityTracker = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return startedTracking;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onBackPressed() {
|
||||||
|
if (startedTracking || checkTransitionAnimation() || fragmentsStack.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (currentActionBar != null && currentActionBar.isSearchFieldVisible) {
|
||||||
|
currentActionBar.closeSearchField();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
BaseFragment lastFragment = fragmentsStack.get(fragmentsStack.size() - 1);
|
||||||
|
if (lastFragment.onBackPressed()) {
|
||||||
|
if (!fragmentsStack.isEmpty()) {
|
||||||
|
closeLastFragment(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onLowMemory() {
|
||||||
|
for (BaseFragment fragment : fragmentsStack) {
|
||||||
|
fragment.onLowMemory();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onAnimationEndCheck(boolean byCheck) {
|
||||||
|
onCloseAnimationEnd(false);
|
||||||
|
onOpenAnimationEnd(false);
|
||||||
|
if (currentAnimation != null) {
|
||||||
|
if (byCheck) {
|
||||||
|
currentAnimation.cancel();
|
||||||
|
}
|
||||||
|
currentAnimation = null;
|
||||||
|
}
|
||||||
|
ViewProxy.setAlpha(this, 1.0f);
|
||||||
|
ViewProxy.setAlpha(containerView, 1.0f);
|
||||||
|
ViewProxy.setScaleX(containerView, 1.0f);
|
||||||
|
ViewProxy.setScaleY(containerView, 1.0f);
|
||||||
|
ViewProxy.setAlpha(containerViewBack, 1.0f);
|
||||||
|
ViewProxy.setScaleX(containerViewBack, 1.0f);
|
||||||
|
ViewProxy.setScaleY(containerViewBack, 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean checkTransitionAnimation() {
|
||||||
|
if (transitionAnimationInProgress && transitionAnimationStartTime < System.currentTimeMillis() - 400) {
|
||||||
|
transitionAnimationInProgress = false;
|
||||||
|
onAnimationEndCheck(true);
|
||||||
|
}
|
||||||
|
return transitionAnimationInProgress;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void presentFragmentInternalRemoveOld(boolean removeLast, final BaseFragment fragment) {
|
||||||
|
if (fragment == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fragment.onPause();
|
||||||
|
if (removeLast) {
|
||||||
|
fragment.onFragmentDestroy();
|
||||||
|
fragment.setParentLayout(null);
|
||||||
|
fragmentsStack.remove(fragment);
|
||||||
|
} else {
|
||||||
|
if (fragment.fragmentView != null) {
|
||||||
|
ViewGroup parent = (ViewGroup) fragment.fragmentView.getParent();
|
||||||
|
if (parent != null) {
|
||||||
|
parent.removeView(fragment.fragmentView);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (fragment.needAddActionBar() && fragment.actionBar != null) {
|
||||||
|
ViewGroup parent = (ViewGroup) fragment.actionBar.getParent();
|
||||||
|
if (parent != null) {
|
||||||
|
parent.removeView(fragment.actionBar);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
containerViewBack.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean presentFragment(BaseFragment fragment) {
|
||||||
|
return presentFragment(fragment, false, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean presentFragment(BaseFragment fragment, boolean removeLast) {
|
||||||
|
return presentFragment(fragment, removeLast, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean presentFragment(final BaseFragment fragment, final boolean removeLast, boolean forceWithoutAnimation, boolean check) {
|
||||||
|
if (checkTransitionAnimation() || delegate != null && check && !delegate.needPresentFragment(fragment, removeLast, forceWithoutAnimation, this) || !fragment.onFragmentCreate()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (parentActivity.getCurrentFocus() != null) {
|
||||||
|
AndroidUtilities.hideKeyboard(parentActivity.getCurrentFocus());
|
||||||
|
NotificationCenter.getInstance().postNotificationName(NotificationCenter.hideEmojiKeyboard);
|
||||||
|
}
|
||||||
|
boolean needAnimation = Build.VERSION.SDK_INT > 10 && !forceWithoutAnimation && parentActivity.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE).getBoolean("view_animations", true);
|
||||||
|
|
||||||
|
final BaseFragment currentFragment = !fragmentsStack.isEmpty() ? fragmentsStack.get(fragmentsStack.size() - 1) : null;
|
||||||
|
|
||||||
|
fragment.setParentLayout(this);
|
||||||
|
View fragmentView = fragment.createView(parentActivity.getLayoutInflater(), null);
|
||||||
|
if (fragment.needAddActionBar() && fragment.actionBar != null) {
|
||||||
|
if (removeActionBarExtraHeight) {
|
||||||
|
fragment.actionBar.setOccupyStatusBar(false);
|
||||||
|
}
|
||||||
|
ViewGroup parent = (ViewGroup) fragment.actionBar.getParent();
|
||||||
|
if (parent != null) {
|
||||||
|
parent.removeView(fragment.actionBar);
|
||||||
|
}
|
||||||
|
containerViewBack.addView(fragment.actionBar);
|
||||||
|
fragment.actionBar.setTitleOverlayText(titleOverlayText);
|
||||||
|
}
|
||||||
|
|
||||||
|
containerViewBack.addView(fragmentView);
|
||||||
|
ViewGroup.LayoutParams layoutParams = fragmentView.getLayoutParams();
|
||||||
|
layoutParams.width = FrameLayout.LayoutParams.MATCH_PARENT;
|
||||||
|
layoutParams.height = FrameLayout.LayoutParams.MATCH_PARENT;
|
||||||
|
fragmentView.setLayoutParams(layoutParams);
|
||||||
|
fragmentsStack.add(fragment);
|
||||||
|
fragment.onResume();
|
||||||
|
currentActionBar = fragment.actionBar;
|
||||||
|
if (fragmentView.getBackground() == null) {
|
||||||
|
fragmentView.setBackgroundColor(0xffffffff);
|
||||||
|
}
|
||||||
|
|
||||||
|
LinearLayoutContainer temp = containerView;
|
||||||
|
containerView = containerViewBack;
|
||||||
|
containerViewBack = temp;
|
||||||
|
containerView.setVisibility(View.VISIBLE);
|
||||||
|
|
||||||
|
bringChildToFront(containerView);
|
||||||
|
|
||||||
|
if (!needAnimation) {
|
||||||
|
presentFragmentInternalRemoveOld(removeLast, currentFragment);
|
||||||
|
if (backgroundView != null) {
|
||||||
|
backgroundView.setVisibility(VISIBLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (needAnimation) {
|
||||||
|
if (useAlphaAnimations && fragmentsStack.size() == 1) {
|
||||||
|
presentFragmentInternalRemoveOld(removeLast, currentFragment);
|
||||||
|
|
||||||
|
ArrayList<Object> animators = new ArrayList<Object>();
|
||||||
|
animators.add(ObjectAnimatorProxy.ofFloat(this, "alpha", 0.0f, 1.0f));
|
||||||
|
if (backgroundView != null) {
|
||||||
|
backgroundView.setVisibility(VISIBLE);
|
||||||
|
animators.add(ObjectAnimatorProxy.ofFloat(backgroundView, "alpha", 0.0f, 1.0f));
|
||||||
|
}
|
||||||
|
|
||||||
|
currentAnimation = new AnimatorSetProxy();
|
||||||
|
currentAnimation.playTogether(animators);
|
||||||
|
currentAnimation.setInterpolator(new AccelerateDecelerateInterpolator());
|
||||||
|
currentAnimation.setDuration(200);
|
||||||
|
currentAnimation.addListener(new AnimatorListenerAdapterProxy() {
|
||||||
|
@Override
|
||||||
|
public void onAnimationEnd(Object animation) {
|
||||||
|
onAnimationEndCheck(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
currentAnimation.start();
|
||||||
|
} else {
|
||||||
|
transitionAnimationStartTime = System.currentTimeMillis();
|
||||||
|
transitionAnimationInProgress = true;
|
||||||
|
onOpenAnimationEndRunnable = new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
presentFragmentInternalRemoveOld(removeLast, currentFragment);
|
||||||
|
fragment.onOpenAnimationEnd();
|
||||||
|
ViewProxy.setTranslationX(containerView, 0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
currentAnimation = new AnimatorSetProxy();
|
||||||
|
currentAnimation.playTogether(
|
||||||
|
ObjectAnimatorProxy.ofFloat(containerView, "alpha", 0.0f, 1.0f),
|
||||||
|
ObjectAnimatorProxy.ofFloat(containerView, "translationX", AndroidUtilities.dp(48), 0));
|
||||||
|
currentAnimation.setInterpolator(new DecelerateInterpolator(1.5f));
|
||||||
|
currentAnimation.setDuration(200);
|
||||||
|
currentAnimation.addListener(new AnimatorListenerAdapterProxy() {
|
||||||
|
@Override
|
||||||
|
public void onAnimationEnd(Object animation) {
|
||||||
|
onAnimationEndCheck(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
currentAnimation.start();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (backgroundView != null) {
|
||||||
|
ViewProxy.setAlpha(backgroundView, 1.0f);
|
||||||
|
backgroundView.setVisibility(VISIBLE);
|
||||||
|
}
|
||||||
|
fragment.onOpenAnimationEnd();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean addFragmentToStack(BaseFragment fragment) {
|
||||||
|
return addFragmentToStack(fragment, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean addFragmentToStack(BaseFragment fragment, int position) {
|
||||||
|
if (delegate != null && !delegate.needAddFragmentToStack(fragment, this) || !fragment.onFragmentCreate()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
fragment.setParentLayout(this);
|
||||||
|
if (position == -1) {
|
||||||
|
fragmentsStack.add(fragment);
|
||||||
|
} else {
|
||||||
|
fragmentsStack.add(position, fragment);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void closeLastFragmentInternalRemoveOld(BaseFragment fragment) {
|
||||||
|
fragment.onPause();
|
||||||
|
fragment.onFragmentDestroy();
|
||||||
|
fragment.setParentLayout(null);
|
||||||
|
fragmentsStack.remove(fragment);
|
||||||
|
containerViewBack.setVisibility(View.GONE);
|
||||||
|
bringChildToFront(containerView);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void closeLastFragment(boolean animated) {
|
||||||
|
if (delegate != null && !delegate.needCloseLastFragment(this) || checkTransitionAnimation()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (parentActivity.getCurrentFocus() != null) {
|
||||||
|
AndroidUtilities.hideKeyboard(parentActivity.getCurrentFocus());
|
||||||
|
}
|
||||||
|
boolean needAnimation = Build.VERSION.SDK_INT > 10 && animated && parentActivity.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE).getBoolean("view_animations", true);
|
||||||
|
final BaseFragment currentFragment = fragmentsStack.get(fragmentsStack.size() - 1);
|
||||||
|
BaseFragment previousFragment = null;
|
||||||
|
if (fragmentsStack.size() > 1) {
|
||||||
|
previousFragment = fragmentsStack.get(fragmentsStack.size() - 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (previousFragment != null) {
|
||||||
|
LinearLayoutContainer temp = containerView;
|
||||||
|
containerView = containerViewBack;
|
||||||
|
containerViewBack = temp;
|
||||||
|
containerView.setVisibility(View.VISIBLE);
|
||||||
|
|
||||||
|
previousFragment.setParentLayout(this);
|
||||||
|
View fragmentView = previousFragment.createView(parentActivity.getLayoutInflater(), null);
|
||||||
|
if (previousFragment.needAddActionBar() && previousFragment.actionBar != null) {
|
||||||
|
if (removeActionBarExtraHeight) {
|
||||||
|
previousFragment.actionBar.setOccupyStatusBar(false);
|
||||||
|
}
|
||||||
|
ViewGroup parent = (ViewGroup) previousFragment.actionBar.getParent();
|
||||||
|
if (parent != null) {
|
||||||
|
parent.removeView(previousFragment.actionBar);
|
||||||
|
}
|
||||||
|
containerView.addView(previousFragment.actionBar);
|
||||||
|
previousFragment.actionBar.setTitleOverlayText(titleOverlayText);
|
||||||
|
}
|
||||||
|
containerView.addView(fragmentView);
|
||||||
|
ViewGroup.LayoutParams layoutParams = fragmentView.getLayoutParams();
|
||||||
|
layoutParams.width = FrameLayout.LayoutParams.MATCH_PARENT;
|
||||||
|
layoutParams.height = FrameLayout.LayoutParams.MATCH_PARENT;
|
||||||
|
fragmentView.setLayoutParams(layoutParams);
|
||||||
|
previousFragment.onResume();
|
||||||
|
currentActionBar = previousFragment.actionBar;
|
||||||
|
if (fragmentView.getBackground() == null) {
|
||||||
|
fragmentView.setBackgroundColor(0xffffffff);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!needAnimation) {
|
||||||
|
closeLastFragmentInternalRemoveOld(currentFragment);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (needAnimation) {
|
||||||
|
transitionAnimationStartTime = System.currentTimeMillis();
|
||||||
|
transitionAnimationInProgress = true;
|
||||||
|
onCloseAnimationEndRunnable = new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
closeLastFragmentInternalRemoveOld(currentFragment);
|
||||||
|
ViewProxy.setTranslationX(containerViewBack, 0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
currentAnimation = new AnimatorSetProxy();
|
||||||
|
currentAnimation.playTogether(
|
||||||
|
ObjectAnimatorProxy.ofFloat(containerViewBack, "alpha", 1.0f, 0.0f),
|
||||||
|
ObjectAnimatorProxy.ofFloat(containerViewBack, "translationX", 0, AndroidUtilities.dp(48)));
|
||||||
|
currentAnimation.setInterpolator(new DecelerateInterpolator(1.5f));
|
||||||
|
currentAnimation.setDuration(200);
|
||||||
|
currentAnimation.addListener(new AnimatorListenerAdapterProxy() {
|
||||||
|
@Override
|
||||||
|
public void onAnimationEnd(Object animation) {
|
||||||
|
onAnimationEndCheck(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
currentAnimation.start();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (useAlphaAnimations) {
|
||||||
|
transitionAnimationStartTime = System.currentTimeMillis();
|
||||||
|
transitionAnimationInProgress = true;
|
||||||
|
|
||||||
|
onCloseAnimationEndRunnable = new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
removeFragmentFromStack(currentFragment);
|
||||||
|
setVisibility(GONE);
|
||||||
|
if (backgroundView != null) {
|
||||||
|
backgroundView.setVisibility(GONE);
|
||||||
|
}
|
||||||
|
if (drawerLayoutContainer != null) {
|
||||||
|
drawerLayoutContainer.setAllowOpenDrawer(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ArrayList<Object> animators = new ArrayList<Object>();
|
||||||
|
animators.add(ObjectAnimatorProxy.ofFloat(this, "alpha", 1.0f, 0.0f));
|
||||||
|
if (backgroundView != null) {
|
||||||
|
animators.add(ObjectAnimatorProxy.ofFloat(backgroundView, "alpha", 1.0f, 0.0f));
|
||||||
|
}
|
||||||
|
|
||||||
|
currentAnimation = new AnimatorSetProxy();
|
||||||
|
currentAnimation.playTogether(animators);
|
||||||
|
currentAnimation.setInterpolator(new AccelerateDecelerateInterpolator());
|
||||||
|
currentAnimation.setDuration(200);
|
||||||
|
currentAnimation.addListener(new AnimatorListenerAdapterProxy() {
|
||||||
|
@Override
|
||||||
|
public void onAnimationEnd(Object animation) {
|
||||||
|
onAnimationEndCheck(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
currentAnimation.start();
|
||||||
|
} else {
|
||||||
|
removeFragmentFromStack(currentFragment);
|
||||||
|
setVisibility(GONE);
|
||||||
|
if (backgroundView != null) {
|
||||||
|
backgroundView.setVisibility(GONE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void showLastFragment() {
|
||||||
|
if (fragmentsStack.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
BaseFragment previousFragment = fragmentsStack.get(fragmentsStack.size() - 1);
|
||||||
|
previousFragment.setParentLayout(this);
|
||||||
|
View fragmentView = previousFragment.createView(parentActivity.getLayoutInflater(), null);
|
||||||
|
if (previousFragment.needAddActionBar() && previousFragment.actionBar != null) {
|
||||||
|
if (removeActionBarExtraHeight) {
|
||||||
|
previousFragment.actionBar.setOccupyStatusBar(false);
|
||||||
|
}
|
||||||
|
ViewGroup parent = (ViewGroup) previousFragment.actionBar.getParent();
|
||||||
|
if (parent != null) {
|
||||||
|
parent.removeView(previousFragment.actionBar);
|
||||||
|
}
|
||||||
|
containerView.addView(previousFragment.actionBar);
|
||||||
|
previousFragment.actionBar.setTitleOverlayText(titleOverlayText);
|
||||||
|
}
|
||||||
|
containerView.addView(fragmentView);
|
||||||
|
ViewGroup.LayoutParams layoutParams = fragmentView.getLayoutParams();
|
||||||
|
layoutParams.width = FrameLayout.LayoutParams.MATCH_PARENT;
|
||||||
|
layoutParams.height = FrameLayout.LayoutParams.MATCH_PARENT;
|
||||||
|
fragmentView.setLayoutParams(layoutParams);
|
||||||
|
previousFragment.onResume();
|
||||||
|
currentActionBar = previousFragment.actionBar;
|
||||||
|
if (fragmentView.getBackground() == null) {
|
||||||
|
fragmentView.setBackgroundColor(0xffffffff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeFragmentFromStack(BaseFragment fragment) {
|
||||||
|
fragment.onPause();
|
||||||
|
fragment.onFragmentDestroy();
|
||||||
|
fragment.setParentLayout(null);
|
||||||
|
fragmentsStack.remove(fragment);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeAllFragments() {
|
||||||
|
for (int a = 0; a < fragmentsStack.size(); a++) {
|
||||||
|
removeFragmentFromStack(fragmentsStack.get(a));
|
||||||
|
a--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void rebuildAllFragmentViews(boolean last) {
|
||||||
|
for (int a = 0; a < fragmentsStack.size() - (last ? 0 : 1); a++) {
|
||||||
|
fragmentsStack.get(a).setParentLayout(null);
|
||||||
|
fragmentsStack.get(a).setParentLayout(this);
|
||||||
|
}
|
||||||
|
if (delegate != null) {
|
||||||
|
delegate.onRebuildAllFragments(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean onKeyUp(int keyCode, KeyEvent event) {
|
||||||
|
if (keyCode == KeyEvent.KEYCODE_MENU && !checkTransitionAnimation() && !startedTracking && currentActionBar != null) {
|
||||||
|
currentActionBar.onMenuButtonPressed();
|
||||||
|
}
|
||||||
|
return super.onKeyUp(keyCode, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onActionModeStarted(ActionMode mode) {
|
||||||
|
if (currentActionBar != null) {
|
||||||
|
currentActionBar.setVisibility(GONE);
|
||||||
|
}
|
||||||
|
inActionMode = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onActionModeFinished(ActionMode mode) {
|
||||||
|
if (currentActionBar != null) {
|
||||||
|
currentActionBar.setVisibility(VISIBLE);
|
||||||
|
}
|
||||||
|
inActionMode = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onCloseAnimationEnd(boolean post) {
|
||||||
|
if (transitionAnimationInProgress && onCloseAnimationEndRunnable != null) {
|
||||||
|
transitionAnimationInProgress = false;
|
||||||
|
transitionAnimationStartTime = 0;
|
||||||
|
if (post) {
|
||||||
|
new Handler().post(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
onCloseAnimationEndRunnable.run();
|
||||||
|
onCloseAnimationEndRunnable = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
onCloseAnimationEndRunnable.run();
|
||||||
|
onCloseAnimationEndRunnable = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onOpenAnimationEnd(boolean post) {
|
||||||
|
if (transitionAnimationInProgress && onOpenAnimationEndRunnable != null) {
|
||||||
|
transitionAnimationInProgress = false;
|
||||||
|
transitionAnimationStartTime = 0;
|
||||||
|
if (post) {
|
||||||
|
new Handler().post(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
onOpenAnimationEndRunnable.run();
|
||||||
|
onOpenAnimationEndRunnable = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
onOpenAnimationEndRunnable.run();
|
||||||
|
onOpenAnimationEndRunnable = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void startActivityForResult(final Intent intent, final int requestCode) {
|
||||||
|
if (parentActivity == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (transitionAnimationInProgress) {
|
||||||
|
if (currentAnimation != null) {
|
||||||
|
currentAnimation.cancel();
|
||||||
|
currentAnimation = null;
|
||||||
|
}
|
||||||
|
if (onCloseAnimationEndRunnable != null) {
|
||||||
|
onCloseAnimationEnd(false);
|
||||||
|
} else if (onOpenAnimationEndRunnable != null) {
|
||||||
|
onOpenAnimationEnd(false);
|
||||||
|
}
|
||||||
|
containerView.invalidate();
|
||||||
|
if (intent != null) {
|
||||||
|
parentActivity.startActivityForResult(intent, requestCode);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (intent != null) {
|
||||||
|
parentActivity.startActivityForResult(intent, requestCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUseAlphaAnimations(boolean value) {
|
||||||
|
useAlphaAnimations = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBackgroundView(View view) {
|
||||||
|
backgroundView = view;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDrawerLayoutContainer(DrawerLayoutContainer layout) {
|
||||||
|
drawerLayoutContainer = layout;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DrawerLayoutContainer getDrawerLayoutContainer() {
|
||||||
|
return drawerLayoutContainer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRemoveActionBarExtraHeight(boolean value) {
|
||||||
|
removeActionBarExtraHeight = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTitleOverlayText(String text) {
|
||||||
|
titleOverlayText = text;
|
||||||
|
for (BaseFragment fragment : fragmentsStack) {
|
||||||
|
if (fragment.actionBar != null) {
|
||||||
|
fragment.actionBar.setTitleOverlayText(titleOverlayText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -6,9 +6,10 @@
|
|||||||
* Copyright Nikolai Kudashov, 2013-2014.
|
* Copyright Nikolai Kudashov, 2013-2014.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.telegram.ui.Views.ActionBar;
|
package org.telegram.ui.ActionBar;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@ -20,14 +21,12 @@ import org.telegram.android.AndroidUtilities;
|
|||||||
|
|
||||||
public class ActionBarMenu extends LinearLayout {
|
public class ActionBarMenu extends LinearLayout {
|
||||||
|
|
||||||
private ActionBar parentActionBar;
|
protected ActionBar parentActionBar;
|
||||||
private ActionBarLayer parentActionBarLayer;
|
|
||||||
|
|
||||||
public ActionBarMenu(Context context, ActionBar actionBar, ActionBarLayer layer) {
|
public ActionBarMenu(Context context, ActionBar layer) {
|
||||||
super(context);
|
super(context);
|
||||||
setOrientation(LinearLayout.HORIZONTAL);
|
setOrientation(LinearLayout.HORIZONTAL);
|
||||||
parentActionBar = actionBar;
|
parentActionBar = layer;
|
||||||
parentActionBarLayer = layer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ActionBarMenu(Context context) {
|
public ActionBarMenu(Context context) {
|
||||||
@ -49,7 +48,7 @@ public class ActionBarMenu extends LinearLayout {
|
|||||||
addView(view);
|
addView(view);
|
||||||
LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams)view.getLayoutParams();
|
LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams)view.getLayoutParams();
|
||||||
layoutParams.height = FrameLayout.LayoutParams.FILL_PARENT;
|
layoutParams.height = FrameLayout.LayoutParams.FILL_PARENT;
|
||||||
view.setBackgroundResource(parentActionBarLayer.itemsBackgroundResourceId);
|
view.setBackgroundResource(parentActionBar.itemsBackgroundResourceId);
|
||||||
view.setLayoutParams(layoutParams);
|
view.setLayoutParams(layoutParams);
|
||||||
view.setOnClickListener(new OnClickListener() {
|
view.setOnClickListener(new OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
@ -60,30 +59,46 @@ public class ActionBarMenu extends LinearLayout {
|
|||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ActionBarMenuItem addItem(int id, Drawable drawable) {
|
||||||
|
return addItem(id, 0, parentActionBar.itemsBackgroundResourceId, drawable, AndroidUtilities.dp(48));
|
||||||
|
}
|
||||||
|
|
||||||
public ActionBarMenuItem addItem(int id, int icon) {
|
public ActionBarMenuItem addItem(int id, int icon) {
|
||||||
return addItem(id, icon, parentActionBarLayer.itemsBackgroundResourceId);
|
return addItem(id, icon, parentActionBar.itemsBackgroundResourceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ActionBarMenuItem addItem(int id, int icon, int backgroundResource) {
|
public ActionBarMenuItem addItem(int id, int icon, int backgroundResource) {
|
||||||
ActionBarMenuItem menuItem = new ActionBarMenuItem(getContext(), this, parentActionBar, backgroundResource);
|
return addItem(id, icon, backgroundResource, null, AndroidUtilities.dp(48));
|
||||||
|
}
|
||||||
|
|
||||||
|
public ActionBarMenuItem addItemWithWidth(int id, int icon, int width) {
|
||||||
|
return addItem(id, icon, parentActionBar.itemsBackgroundResourceId, null, width);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ActionBarMenuItem addItem(int id, int icon, int backgroundResource, Drawable drawable, int width) {
|
||||||
|
ActionBarMenuItem menuItem = new ActionBarMenuItem(getContext(), this, backgroundResource);
|
||||||
menuItem.setTag(id);
|
menuItem.setTag(id);
|
||||||
menuItem.setScaleType(ImageView.ScaleType.CENTER);
|
menuItem.setScaleType(ImageView.ScaleType.CENTER);
|
||||||
menuItem.setImageResource(icon);
|
if (drawable != null) {
|
||||||
|
menuItem.setImageDrawable(drawable);
|
||||||
|
} else {
|
||||||
|
menuItem.setImageResource(icon);
|
||||||
|
}
|
||||||
addView(menuItem);
|
addView(menuItem);
|
||||||
LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams)menuItem.getLayoutParams();
|
LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams)menuItem.getLayoutParams();
|
||||||
layoutParams.height = FrameLayout.LayoutParams.MATCH_PARENT;
|
layoutParams.height = FrameLayout.LayoutParams.MATCH_PARENT;
|
||||||
layoutParams.width = AndroidUtilities.dp(56);
|
layoutParams.width = width;
|
||||||
menuItem.setLayoutParams(layoutParams);
|
menuItem.setLayoutParams(layoutParams);
|
||||||
menuItem.setOnClickListener(new OnClickListener() {
|
menuItem.setOnClickListener(new OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View view) {
|
public void onClick(View view) {
|
||||||
ActionBarMenuItem item = (ActionBarMenuItem)view;
|
ActionBarMenuItem item = (ActionBarMenuItem)view;
|
||||||
if (item.hasSubMenu()) {
|
if (item.hasSubMenu()) {
|
||||||
if (parentActionBarLayer.actionBarMenuOnItemClick.canOpenMenu()) {
|
if (parentActionBar.actionBarMenuOnItemClick.canOpenMenu()) {
|
||||||
item.toggleSubMenu();
|
item.toggleSubMenu();
|
||||||
}
|
}
|
||||||
} else if (item.isSearchField()) {
|
} else if (item.isSearchField()) {
|
||||||
parentActionBarLayer.onSearchFieldVisibilityChanged(item.toggleSearch());
|
parentActionBar.onSearchFieldVisibilityChanged(item.toggleSearch());
|
||||||
} else {
|
} else {
|
||||||
onItemClick((Integer)view.getTag());
|
onItemClick((Integer)view.getTag());
|
||||||
}
|
}
|
||||||
@ -102,8 +117,8 @@ public class ActionBarMenu extends LinearLayout {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void onItemClick(int id) {
|
public void onItemClick(int id) {
|
||||||
if (parentActionBarLayer.actionBarMenuOnItemClick != null) {
|
if (parentActionBar.actionBarMenuOnItemClick != null) {
|
||||||
parentActionBarLayer.actionBarMenuOnItemClick.onItemClick(id);
|
parentActionBar.actionBarMenuOnItemClick.onItemClick(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,8 +134,9 @@ public class ActionBarMenu extends LinearLayout {
|
|||||||
View view = getChildAt(a);
|
View view = getChildAt(a);
|
||||||
if (view instanceof ActionBarMenuItem) {
|
if (view instanceof ActionBarMenuItem) {
|
||||||
ActionBarMenuItem item = (ActionBarMenuItem)view;
|
ActionBarMenuItem item = (ActionBarMenuItem)view;
|
||||||
if (item.hasSubMenu()) {
|
if (item.hasSubMenu() && item.getVisibility() == VISIBLE) {
|
||||||
item.toggleSubMenu();
|
item.toggleSubMenu();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -132,7 +148,7 @@ public class ActionBarMenu extends LinearLayout {
|
|||||||
if (view instanceof ActionBarMenuItem) {
|
if (view instanceof ActionBarMenuItem) {
|
||||||
ActionBarMenuItem item = (ActionBarMenuItem)view;
|
ActionBarMenuItem item = (ActionBarMenuItem)view;
|
||||||
if (item.isSearchField()) {
|
if (item.isSearchField()) {
|
||||||
parentActionBarLayer.onSearchFieldVisibilityChanged(item.toggleSearch());
|
parentActionBar.onSearchFieldVisibilityChanged(item.toggleSearch());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -6,14 +6,13 @@
|
|||||||
* Copyright Nikolai Kudashov, 2013-2014.
|
* Copyright Nikolai Kudashov, 2013-2014.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.telegram.ui.Views.ActionBar;
|
package org.telegram.ui.ActionBar;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.text.Editable;
|
import android.text.Editable;
|
||||||
import android.text.TextWatcher;
|
import android.text.TextWatcher;
|
||||||
import android.util.AttributeSet;
|
|
||||||
import android.view.ActionMode;
|
import android.view.ActionMode;
|
||||||
import android.view.ContextMenu;
|
import android.view.ContextMenu;
|
||||||
import android.view.Gravity;
|
import android.view.Gravity;
|
||||||
@ -47,36 +46,39 @@ public class ActionBarMenuItem extends ImageView {
|
|||||||
private ActionBarPopupWindow.ActionBarPopupWindowLayout popupLayout;
|
private ActionBarPopupWindow.ActionBarPopupWindowLayout popupLayout;
|
||||||
private ActionBarMenu parentMenu;
|
private ActionBarMenu parentMenu;
|
||||||
private ActionBarPopupWindow popupWindow;
|
private ActionBarPopupWindow popupWindow;
|
||||||
private ActionBar parentActionBar;
|
|
||||||
private EditText searchField;
|
private EditText searchField;
|
||||||
private boolean isSearchField = false;
|
private boolean isSearchField = false;
|
||||||
private ActionBarMenuItemSearchListener listener;
|
private ActionBarMenuItemSearchListener listener;
|
||||||
private Rect rect = null;
|
private Rect rect;
|
||||||
private int[] location = null;
|
private int[] location;
|
||||||
private View selectedMenuView = null;
|
private View selectedMenuView;
|
||||||
|
private Runnable showMenuRunnable;
|
||||||
|
private boolean showFromBottom;
|
||||||
|
private int menuHeight = AndroidUtilities.dp(16);
|
||||||
|
private boolean needOffset = Build.VERSION.SDK_INT >= 21;
|
||||||
|
|
||||||
public ActionBarMenuItem(Context context, ActionBarMenu menu, ActionBar actionBar, int background) {
|
public ActionBarMenuItem(Context context, ActionBarMenu menu, int background) {
|
||||||
super(context);
|
super(context);
|
||||||
setBackgroundResource(background);
|
setBackgroundResource(background);
|
||||||
parentMenu = menu;
|
parentMenu = menu;
|
||||||
parentActionBar = actionBar;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ActionBarMenuItem(Context context) {
|
|
||||||
super(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ActionBarMenuItem(Context context, AttributeSet attrs) {
|
|
||||||
super(context, attrs);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ActionBarMenuItem(Context context, AttributeSet attrs, int defStyleAttr) {
|
|
||||||
super(context, attrs, defStyleAttr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onTouchEvent(MotionEvent event) {
|
public boolean onTouchEvent(MotionEvent event) {
|
||||||
if (event.getActionMasked() == MotionEvent.ACTION_MOVE) {
|
if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
|
||||||
|
if (hasSubMenu() && (popupWindow == null || popupWindow != null && !popupWindow.isShowing())) {
|
||||||
|
showMenuRunnable = new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (getParent() != null) {
|
||||||
|
getParent().requestDisallowInterceptTouchEvent(true);
|
||||||
|
}
|
||||||
|
toggleSubMenu();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
AndroidUtilities.runOnUIThread(showMenuRunnable, 200);
|
||||||
|
}
|
||||||
|
} else if (event.getActionMasked() == MotionEvent.ACTION_MOVE) {
|
||||||
if (hasSubMenu() && (popupWindow == null || popupWindow != null && !popupWindow.isShowing())) {
|
if (hasSubMenu() && (popupWindow == null || popupWindow != null && !popupWindow.isShowing())) {
|
||||||
if (event.getY() > getHeight()) {
|
if (event.getY() > getHeight()) {
|
||||||
if (getParent() != null) {
|
if (getParent() != null) {
|
||||||
@ -98,9 +100,18 @@ public class ActionBarMenuItem extends ImageView {
|
|||||||
child.getHitRect(rect);
|
child.getHitRect(rect);
|
||||||
if ((Integer)child.getTag() < 100) {
|
if ((Integer)child.getTag() < 100) {
|
||||||
if (!rect.contains((int)x, (int)y)) {
|
if (!rect.contains((int)x, (int)y)) {
|
||||||
|
child.setPressed(false);
|
||||||
child.setSelected(false);
|
child.setSelected(false);
|
||||||
|
if (Build.VERSION.SDK_INT >= 21) {
|
||||||
|
child.getBackground().setVisible(false, false);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
child.setPressed(true);
|
||||||
child.setSelected(true);
|
child.setSelected(true);
|
||||||
|
if (Build.VERSION.SDK_INT >= 21) {
|
||||||
|
child.getBackground().setVisible(true, false);
|
||||||
|
child.drawableHotspotChanged(x, y - child.getTop());
|
||||||
|
}
|
||||||
selectedMenuView = child;
|
selectedMenuView = child;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -121,7 +132,15 @@ public class ActionBarMenuItem extends ImageView {
|
|||||||
return super.onTouchEvent(event);
|
return super.onTouchEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addSubItem(int id, String text, int icon) {
|
public void setShowFromBottom(boolean value) {
|
||||||
|
showFromBottom = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNeedOffset(boolean value) {
|
||||||
|
needOffset = Build.VERSION.SDK_INT >= 21 && value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TextView addSubItem(int id, String text, int icon) {
|
||||||
if (popupLayout == null) {
|
if (popupLayout == null) {
|
||||||
rect = new Rect();
|
rect = new Rect();
|
||||||
location = new int[2];
|
location = new int[2];
|
||||||
@ -151,18 +170,8 @@ public class ActionBarMenuItem extends ImageView {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (popupLayout.getChildCount() != 0) {
|
|
||||||
View delimeter = new View(getContext());
|
|
||||||
delimeter.setBackgroundColor(0xffdcdcdc);
|
|
||||||
popupLayout.addView(delimeter);
|
|
||||||
LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams)delimeter.getLayoutParams();
|
|
||||||
layoutParams.width = LinearLayout.LayoutParams.MATCH_PARENT;
|
|
||||||
layoutParams.height = AndroidUtilities.density >= 3 ? 2 : 1;
|
|
||||||
delimeter.setLayoutParams(layoutParams);
|
|
||||||
delimeter.setTag(100 + id);
|
|
||||||
}
|
|
||||||
TextView textView = new TextView(getContext());
|
TextView textView = new TextView(getContext());
|
||||||
textView.setTextColor(0xff000000);
|
textView.setTextColor(0xff212121);
|
||||||
textView.setBackgroundResource(R.drawable.list_selector);
|
textView.setBackgroundResource(R.drawable.list_selector);
|
||||||
if (!LocaleController.isRTL) {
|
if (!LocaleController.isRTL) {
|
||||||
textView.setGravity(Gravity.CENTER_VERTICAL);
|
textView.setGravity(Gravity.CENTER_VERTICAL);
|
||||||
@ -187,7 +196,7 @@ public class ActionBarMenuItem extends ImageView {
|
|||||||
if (LocaleController.isRTL) {
|
if (LocaleController.isRTL) {
|
||||||
layoutParams.gravity = Gravity.RIGHT;
|
layoutParams.gravity = Gravity.RIGHT;
|
||||||
}
|
}
|
||||||
layoutParams.width = LinearLayout.LayoutParams.WRAP_CONTENT;
|
layoutParams.width = LinearLayout.LayoutParams.MATCH_PARENT;
|
||||||
layoutParams.height = AndroidUtilities.dp(48);
|
layoutParams.height = AndroidUtilities.dp(48);
|
||||||
textView.setLayoutParams(layoutParams);
|
textView.setLayoutParams(layoutParams);
|
||||||
textView.setOnClickListener(new OnClickListener() {
|
textView.setOnClickListener(new OnClickListener() {
|
||||||
@ -199,6 +208,8 @@ public class ActionBarMenuItem extends ImageView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
menuHeight += layoutParams.height;
|
||||||
|
return textView;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasSubMenu() {
|
public boolean hasSubMenu() {
|
||||||
@ -206,6 +217,13 @@ public class ActionBarMenuItem extends ImageView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void toggleSubMenu() {
|
public void toggleSubMenu() {
|
||||||
|
if (popupLayout == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (showMenuRunnable != null) {
|
||||||
|
AndroidUtilities.cancelRunOnUIThread(showMenuRunnable);
|
||||||
|
showMenuRunnable = null;
|
||||||
|
}
|
||||||
if (popupWindow != null && popupWindow.isShowing()) {
|
if (popupWindow != null && popupWindow.isShowing()) {
|
||||||
popupWindow.dismiss();
|
popupWindow.dismiss();
|
||||||
return;
|
return;
|
||||||
@ -213,6 +231,7 @@ public class ActionBarMenuItem extends ImageView {
|
|||||||
if (popupWindow == null) {
|
if (popupWindow == null) {
|
||||||
popupWindow = new ActionBarPopupWindow(popupLayout, FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT);
|
popupWindow = new ActionBarPopupWindow(popupLayout, FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT);
|
||||||
//popupWindow.setBackgroundDrawable(new BitmapDrawable());
|
//popupWindow.setBackgroundDrawable(new BitmapDrawable());
|
||||||
|
popupWindow.setAnimationStyle(R.style.PopupAnimation);
|
||||||
popupWindow.setOutsideTouchable(true);
|
popupWindow.setOutsideTouchable(true);
|
||||||
popupWindow.setClippingEnabled(true);
|
popupWindow.setClippingEnabled(true);
|
||||||
popupWindow.setInputMethodMode(ActionBarPopupWindow.INPUT_METHOD_NOT_NEEDED);
|
popupWindow.setInputMethodMode(ActionBarPopupWindow.INPUT_METHOD_NOT_NEEDED);
|
||||||
@ -232,10 +251,33 @@ public class ActionBarMenuItem extends ImageView {
|
|||||||
}
|
}
|
||||||
popupWindow.setFocusable(true);
|
popupWindow.setFocusable(true);
|
||||||
if (popupLayout.getMeasuredWidth() == 0) {
|
if (popupLayout.getMeasuredWidth() == 0) {
|
||||||
popupWindow.showAsDropDown(this, parentActionBar.getMeasuredWidth() - popupLayout.getMeasuredWidth() - getLeft() - parentMenu.getLeft(), 0);
|
if (showFromBottom) {
|
||||||
popupWindow.update(this, parentActionBar.getMeasuredWidth() - popupLayout.getMeasuredWidth() - getLeft() - parentMenu.getLeft(), 0, -1, -1);
|
popupWindow.showAsDropDown(this, -popupLayout.getMeasuredWidth() + getMeasuredWidth() + AndroidUtilities.dp(14), getOffsetY());
|
||||||
|
popupWindow.update(this, -popupLayout.getMeasuredWidth() + getMeasuredWidth() + AndroidUtilities.dp(14), getOffsetY(), -1, -1);
|
||||||
|
} else {
|
||||||
|
popupWindow.showAsDropDown(this, parentMenu.parentActionBar.getMeasuredWidth() - popupLayout.getMeasuredWidth() - getLeft() - parentMenu.getLeft(), getOffsetY());
|
||||||
|
popupWindow.update(this, parentMenu.parentActionBar.getMeasuredWidth() - popupLayout.getMeasuredWidth() - getLeft() - parentMenu.getLeft(), getOffsetY(), -1, -1);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
popupWindow.showAsDropDown(this, parentActionBar.getMeasuredWidth() - popupLayout.getMeasuredWidth() - getLeft() - parentMenu.getLeft(), 0);
|
if (showFromBottom) {
|
||||||
|
popupWindow.showAsDropDown(this, -popupLayout.getMeasuredWidth() + getMeasuredWidth() + AndroidUtilities.dp(14), getOffsetY());
|
||||||
|
} else {
|
||||||
|
popupWindow.showAsDropDown(this, parentMenu.parentActionBar.getMeasuredWidth() - popupLayout.getMeasuredWidth() - getLeft() - parentMenu.getLeft(), getOffsetY());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getOffsetY() {
|
||||||
|
if (showFromBottom) {
|
||||||
|
getLocationOnScreen(location);
|
||||||
|
int diff = location[1] - AndroidUtilities.statusBarHeight + getMeasuredHeight() - menuHeight;
|
||||||
|
int y = AndroidUtilities.dp(8) - menuHeight;
|
||||||
|
if (diff < 0) {
|
||||||
|
y -= diff;
|
||||||
|
}
|
||||||
|
return y - (needOffset ? AndroidUtilities.statusBarHeight : 0);
|
||||||
|
} else {
|
||||||
|
return -getMeasuredHeight() - (needOffset ? AndroidUtilities.statusBarHeight : 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -281,7 +323,7 @@ public class ActionBarMenuItem extends ImageView {
|
|||||||
searchField.setTextColor(0xffffffff);
|
searchField.setTextColor(0xffffffff);
|
||||||
searchField.setSingleLine(true);
|
searchField.setSingleLine(true);
|
||||||
searchField.setBackgroundResource(R.drawable.search_light_states);
|
searchField.setBackgroundResource(R.drawable.search_light_states);
|
||||||
searchField.setPadding(AndroidUtilities.dp(6), 0, AndroidUtilities.dp(6), 0);
|
searchField.setPadding(0, 0, 0, 0);
|
||||||
searchField.setInputType(EditorInfo.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
|
searchField.setInputType(EditorInfo.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
|
||||||
if (android.os.Build.VERSION.SDK_INT < 11) {
|
if (android.os.Build.VERSION.SDK_INT < 11) {
|
||||||
searchField.setOnCreateContextMenuListener(new OnCreateContextMenuListener() {
|
searchField.setOnCreateContextMenuListener(new OnCreateContextMenuListener() {
|
||||||
@ -360,7 +402,8 @@ public class ActionBarMenuItem extends ImageView {
|
|||||||
layoutParams.width = 0;
|
layoutParams.width = 0;
|
||||||
layoutParams.gravity = Gravity.CENTER_VERTICAL;
|
layoutParams.gravity = Gravity.CENTER_VERTICAL;
|
||||||
layoutParams.height = AndroidUtilities.dp(36);
|
layoutParams.height = AndroidUtilities.dp(36);
|
||||||
layoutParams.rightMargin = AndroidUtilities.dp(4);
|
layoutParams.rightMargin = AndroidUtilities.dp(22);
|
||||||
|
layoutParams.leftMargin = AndroidUtilities.dp(6);
|
||||||
searchField.setLayoutParams(layoutParams);
|
searchField.setLayoutParams(layoutParams);
|
||||||
searchField.setVisibility(GONE);
|
searchField.setVisibility(GONE);
|
||||||
}
|
}
|
||||||
@ -377,10 +420,14 @@ public class ActionBarMenuItem extends ImageView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
super.onLayout(changed, left, top, right, bottom);
|
||||||
if (popupWindow != null && popupWindow.isShowing()) {
|
if (popupWindow != null && popupWindow.isShowing()) {
|
||||||
popupWindow.update(this, parentActionBar.getMeasuredWidth() - popupLayout.getMeasuredWidth() - getLeft() - parentMenu.getLeft(), 0, -1, -1);
|
if (showFromBottom) {
|
||||||
|
popupWindow.update(this, -popupLayout.getMeasuredWidth() + getMeasuredWidth() + AndroidUtilities.dp(14), getOffsetY(), -1, -1);
|
||||||
|
} else {
|
||||||
|
popupWindow.update(this, parentMenu.parentActionBar.getMeasuredWidth() - popupLayout.getMeasuredWidth() - getLeft() - parentMenu.getLeft(), getOffsetY(), -1, -1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -8,19 +8,24 @@
|
|||||||
|
|
||||||
//Thanks to https://github.com/JakeWharton/ActionBarSherlock/
|
//Thanks to https://github.com/JakeWharton/ActionBarSherlock/
|
||||||
|
|
||||||
package org.telegram.ui.Views.ActionBar;
|
package org.telegram.ui.ActionBar;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.os.Build;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewTreeObserver;
|
import android.view.ViewTreeObserver;
|
||||||
|
import android.view.WindowManager;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.PopupWindow;
|
import android.widget.PopupWindow;
|
||||||
|
|
||||||
|
import org.telegram.messenger.FileLog;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
|
||||||
public class ActionBarPopupWindow extends PopupWindow {
|
public class ActionBarPopupWindow extends PopupWindow {
|
||||||
|
|
||||||
private static final Field superListenerField;
|
private static final Field superListenerField;
|
||||||
static {
|
static {
|
||||||
Field f = null;
|
Field f = null;
|
||||||
@ -130,6 +135,15 @@ public class ActionBarPopupWindow extends PopupWindow {
|
|||||||
mSuperScrollListener = null;
|
mSuperScrollListener = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (Build.VERSION.SDK_INT >= 21) {
|
||||||
|
try {
|
||||||
|
Field field = PopupWindow.class.getDeclaredField("mWindowLayoutType");
|
||||||
|
field.setAccessible(true);
|
||||||
|
field.set(this, WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
|
||||||
|
} catch (Exception e) {
|
||||||
|
/* ignored */
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void unregisterListener() {
|
private void unregisterListener() {
|
||||||
@ -157,8 +171,12 @@ public class ActionBarPopupWindow extends PopupWindow {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void showAsDropDown(View anchor, int xoff, int yoff) {
|
public void showAsDropDown(View anchor, int xoff, int yoff) {
|
||||||
super.showAsDropDown(anchor, xoff, yoff);
|
try {
|
||||||
registerListener(anchor);
|
super.showAsDropDown(anchor, xoff, yoff);
|
||||||
|
registerListener(anchor);
|
||||||
|
} catch (Exception e) {
|
||||||
|
FileLog.e("tmessages", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
@ -6,7 +6,7 @@
|
|||||||
* Copyright Nikolai Kudashov, 2013.
|
* Copyright Nikolai Kudashov, 2013.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.telegram.ui.Views.ActionBar;
|
package org.telegram.ui.ActionBar;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
@ -23,12 +23,13 @@ import org.telegram.messenger.R;
|
|||||||
|
|
||||||
public class BaseFragment {
|
public class BaseFragment {
|
||||||
private boolean isFinished = false;
|
private boolean isFinished = false;
|
||||||
|
private AlertDialog visibleDialog = null;
|
||||||
|
|
||||||
protected View fragmentView;
|
protected View fragmentView;
|
||||||
protected ActionBarLayout parentLayout;
|
protected ActionBarLayout parentLayout;
|
||||||
protected ActionBarLayer actionBarLayer;
|
protected ActionBar actionBar;
|
||||||
protected int classGuid = 0;
|
protected int classGuid = 0;
|
||||||
protected Bundle arguments;
|
protected Bundle arguments;
|
||||||
private AlertDialog visibleDialog = null;
|
|
||||||
protected boolean swipeBackEnabled = true;
|
protected boolean swipeBackEnabled = true;
|
||||||
|
|
||||||
public BaseFragment() {
|
public BaseFragment() {
|
||||||
@ -48,7 +49,7 @@ public class BaseFragment {
|
|||||||
return arguments;
|
return arguments;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setParentLayout(ActionBarLayout layout) {
|
protected void setParentLayout(ActionBarLayout layout) {
|
||||||
if (parentLayout != layout) {
|
if (parentLayout != layout) {
|
||||||
parentLayout = layout;
|
parentLayout = layout;
|
||||||
if (fragmentView != null) {
|
if (fragmentView != null) {
|
||||||
@ -62,14 +63,21 @@ public class BaseFragment {
|
|||||||
}
|
}
|
||||||
fragmentView = null;
|
fragmentView = null;
|
||||||
}
|
}
|
||||||
if (parentLayout != null) {
|
if (actionBar != null) {
|
||||||
if (actionBarLayer != null) {
|
ViewGroup parent = (ViewGroup) actionBar.getParent();
|
||||||
actionBarLayer.onDestroy();
|
if (parent != null) {
|
||||||
|
try {
|
||||||
|
parent.removeView(actionBar);
|
||||||
|
} catch (Exception e) {
|
||||||
|
FileLog.e("tmessages", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
actionBarLayer = parentLayout.getInternalActionBar().createLayer();
|
}
|
||||||
actionBarLayer.parentFragment = this;
|
if (parentLayout != null) {
|
||||||
actionBarLayer.setBackgroundResource(R.color.header);
|
actionBar = new ActionBar(parentLayout.getContext());
|
||||||
actionBarLayer.setItemsBackground(R.drawable.bar_selector);
|
actionBar.parentFragment = this;
|
||||||
|
actionBar.setBackgroundResource(R.color.header);
|
||||||
|
actionBar.setItemsBackground(R.drawable.bar_selector);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -99,8 +107,8 @@ public class BaseFragment {
|
|||||||
public void onFragmentDestroy() {
|
public void onFragmentDestroy() {
|
||||||
ConnectionsManager.getInstance().cancelRpcsForClassGuid(classGuid);
|
ConnectionsManager.getInstance().cancelRpcsForClassGuid(classGuid);
|
||||||
isFinished = true;
|
isFinished = true;
|
||||||
if (actionBarLayer != null) {
|
if (actionBar != null) {
|
||||||
actionBarLayer.setEnabled(false);
|
actionBar.setEnabled(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,9 +117,8 @@ public class BaseFragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void onPause() {
|
public void onPause() {
|
||||||
if (actionBarLayer != null) {
|
if (actionBar != null) {
|
||||||
actionBarLayer.onPause();
|
actionBar.onPause();
|
||||||
actionBarLayer.closeSearchField();
|
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
if (visibleDialog != null && visibleDialog.isShowing()) {
|
if (visibleDialog != null && visibleDialog.isShowing()) {
|
||||||
@ -168,18 +175,6 @@ public class BaseFragment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void showActionBar() {
|
|
||||||
if (parentLayout != null) {
|
|
||||||
parentLayout.showActionBar();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void hideActionBar() {
|
|
||||||
if (parentLayout != null) {
|
|
||||||
parentLayout.hideActionBar();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onBeginSlide() {
|
public void onBeginSlide() {
|
||||||
try {
|
try {
|
||||||
if (visibleDialog != null && visibleDialog.isShowing()) {
|
if (visibleDialog != null && visibleDialog.isShowing()) {
|
||||||
@ -189,8 +184,8 @@ public class BaseFragment {
|
|||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
FileLog.e("tmessages", e);
|
FileLog.e("tmessages", e);
|
||||||
}
|
}
|
||||||
if (actionBarLayer != null) {
|
if (actionBar != null) {
|
||||||
actionBarLayer.onPause();
|
actionBar.onPause();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -202,6 +197,10 @@ public class BaseFragment {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean needAddActionBar() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
protected void showAlertDialog(AlertDialog.Builder builder) {
|
protected void showAlertDialog(AlertDialog.Builder builder) {
|
||||||
if (parentLayout == null || parentLayout.checkTransitionAnimation() || parentLayout.animationInProgress || parentLayout.startedTracking) {
|
if (parentLayout == null || parentLayout.checkTransitionAnimation() || parentLayout.animationInProgress || parentLayout.startedTracking) {
|
||||||
return;
|
return;
|
||||||
@ -214,15 +213,19 @@ public class BaseFragment {
|
|||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
FileLog.e("tmessages", e);
|
FileLog.e("tmessages", e);
|
||||||
}
|
}
|
||||||
visibleDialog = builder.show();
|
try {
|
||||||
visibleDialog.setCanceledOnTouchOutside(true);
|
visibleDialog = builder.show();
|
||||||
visibleDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
|
visibleDialog.setCanceledOnTouchOutside(true);
|
||||||
@Override
|
visibleDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
|
||||||
public void onDismiss(DialogInterface dialog) {
|
@Override
|
||||||
visibleDialog = null;
|
public void onDismiss(DialogInterface dialog) {
|
||||||
onDialogDismiss();
|
visibleDialog = null;
|
||||||
}
|
onDialogDismiss();
|
||||||
});
|
}
|
||||||
|
});
|
||||||
|
} catch (Exception e) {
|
||||||
|
FileLog.e("tmessages", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void onDialogDismiss() {
|
protected void onDialogDismiss() {
|
@ -0,0 +1,477 @@
|
|||||||
|
/*
|
||||||
|
* This is the source code of Telegram for Android v. 1.7.x.
|
||||||
|
* It is licensed under GNU GPL v. 2 or later.
|
||||||
|
* You should have received a copy of the license in this archive (see LICENSE).
|
||||||
|
*
|
||||||
|
* Copyright Nikolai Kudashov, 2013-2014.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.telegram.ui.ActionBar;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.view.Gravity;
|
||||||
|
import android.view.MotionEvent;
|
||||||
|
import android.view.VelocityTracker;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.view.WindowInsets;
|
||||||
|
import android.view.animation.DecelerateInterpolator;
|
||||||
|
import android.widget.FrameLayout;
|
||||||
|
import android.widget.ListView;
|
||||||
|
|
||||||
|
import org.telegram.android.AndroidUtilities;
|
||||||
|
import org.telegram.messenger.R;
|
||||||
|
import org.telegram.ui.AnimationCompat.AnimatorListenerAdapterProxy;
|
||||||
|
import org.telegram.ui.AnimationCompat.AnimatorSetProxy;
|
||||||
|
import org.telegram.ui.AnimationCompat.ObjectAnimatorProxy;
|
||||||
|
|
||||||
|
public class DrawerLayoutContainer extends FrameLayout {
|
||||||
|
|
||||||
|
private static final int MIN_DRAWER_MARGIN = 64;
|
||||||
|
|
||||||
|
private ViewGroup drawerLayout;
|
||||||
|
private ActionBarLayout parentActionBarLayout;
|
||||||
|
|
||||||
|
private boolean maybeStartTracking = false;
|
||||||
|
private boolean startedTracking = false;
|
||||||
|
private int startedTrackingX;
|
||||||
|
private int startedTrackingY;
|
||||||
|
private int startedTrackingPointerId;
|
||||||
|
private VelocityTracker velocityTracker = null;
|
||||||
|
private boolean beginTrackingSent;
|
||||||
|
private AnimatorSetProxy currentAnimation = null;
|
||||||
|
|
||||||
|
private Paint scrimPaint = new Paint();
|
||||||
|
|
||||||
|
private Object lastInsets;
|
||||||
|
private boolean inLayout;
|
||||||
|
private int minDrawerMargin;
|
||||||
|
private float scrimOpacity;
|
||||||
|
private Drawable shadowLeft;
|
||||||
|
private boolean allowOpenDrawer;
|
||||||
|
|
||||||
|
private float drawerPosition = 0;
|
||||||
|
private boolean drawerOpened = false;
|
||||||
|
|
||||||
|
public DrawerLayoutContainer(Context context) {
|
||||||
|
super(context);
|
||||||
|
|
||||||
|
minDrawerMargin = (int) (MIN_DRAWER_MARGIN * AndroidUtilities.density + 0.5f);
|
||||||
|
setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
|
||||||
|
setFocusableInTouchMode(true);
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= 21) {
|
||||||
|
setFitsSystemWindows(true);
|
||||||
|
configureApplyInsets(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
shadowLeft = getResources().getDrawable(R.drawable.menu_shadow);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class InsetsListener implements View.OnApplyWindowInsetsListener {
|
||||||
|
@Override
|
||||||
|
public WindowInsets onApplyWindowInsets(View v, WindowInsets insets) {
|
||||||
|
final DrawerLayoutContainer drawerLayout = (DrawerLayoutContainer) v;
|
||||||
|
drawerLayout.setChildInsets(insets, insets.getSystemWindowInsetTop() > 0);
|
||||||
|
return insets.consumeSystemWindowInsets();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void configureApplyInsets(View drawerLayout) {
|
||||||
|
if (Build.VERSION.SDK_INT >= 21) {
|
||||||
|
drawerLayout.setOnApplyWindowInsetsListener(new InsetsListener());
|
||||||
|
drawerLayout.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void dispatchChildInsets(View child, Object insets, int drawerGravity) {
|
||||||
|
WindowInsets wi = (WindowInsets) insets;
|
||||||
|
if (drawerGravity == Gravity.LEFT) {
|
||||||
|
wi = wi.replaceSystemWindowInsets(wi.getSystemWindowInsetLeft(), wi.getSystemWindowInsetTop(), 0, wi.getSystemWindowInsetBottom());
|
||||||
|
} else if (drawerGravity == Gravity.RIGHT) {
|
||||||
|
wi = wi.replaceSystemWindowInsets(0, wi.getSystemWindowInsetTop(), wi.getSystemWindowInsetRight(), wi.getSystemWindowInsetBottom());
|
||||||
|
}
|
||||||
|
child.dispatchApplyWindowInsets(wi);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applyMarginInsets(MarginLayoutParams lp, Object insets, int drawerGravity, boolean topOnly) {
|
||||||
|
WindowInsets wi = (WindowInsets) insets;
|
||||||
|
if (drawerGravity == Gravity.LEFT) {
|
||||||
|
wi = wi.replaceSystemWindowInsets(wi.getSystemWindowInsetLeft(), wi.getSystemWindowInsetTop(), 0, wi.getSystemWindowInsetBottom());
|
||||||
|
} else if (drawerGravity == Gravity.RIGHT) {
|
||||||
|
wi = wi.replaceSystemWindowInsets(0, wi.getSystemWindowInsetTop(), wi.getSystemWindowInsetRight(), wi.getSystemWindowInsetBottom());
|
||||||
|
}
|
||||||
|
lp.leftMargin = wi.getSystemWindowInsetLeft();
|
||||||
|
lp.topMargin = topOnly ? 0 : wi.getSystemWindowInsetTop();
|
||||||
|
lp.rightMargin = wi.getSystemWindowInsetRight();
|
||||||
|
lp.bottomMargin = wi.getSystemWindowInsetBottom();
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getTopInset(Object insets) {
|
||||||
|
if (Build.VERSION.SDK_INT >= 21) {
|
||||||
|
return insets != null ? ((WindowInsets) insets).getSystemWindowInsetTop() : 0;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setChildInsets(Object insets, boolean draw) {
|
||||||
|
lastInsets = insets;
|
||||||
|
setWillNotDraw(!draw && getBackground() == null);
|
||||||
|
requestLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDrawerLayout(ViewGroup layout) {
|
||||||
|
drawerLayout = layout;
|
||||||
|
addView(drawerLayout);
|
||||||
|
if (Build.VERSION.SDK_INT >= 21) {
|
||||||
|
drawerLayout.setFitsSystemWindows(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void moveDrawerByX(float dx) {
|
||||||
|
setDrawerPosition(drawerPosition + dx);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDrawerPosition(float value) {
|
||||||
|
drawerPosition = value;
|
||||||
|
if (drawerPosition > drawerLayout.getMeasuredWidth()) {
|
||||||
|
drawerPosition = drawerLayout.getMeasuredWidth();
|
||||||
|
} else if (drawerPosition < 0) {
|
||||||
|
drawerPosition = 0;
|
||||||
|
}
|
||||||
|
requestLayout();
|
||||||
|
|
||||||
|
final int newVisibility = drawerPosition > 0 ? VISIBLE : INVISIBLE;
|
||||||
|
if (drawerLayout.getVisibility() != newVisibility) {
|
||||||
|
drawerLayout.setVisibility(newVisibility);
|
||||||
|
}
|
||||||
|
setScrimOpacity(drawerPosition / (float)drawerLayout.getMeasuredWidth());
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getDrawerPosition() {
|
||||||
|
return drawerPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cancelCurrentAnimation() {
|
||||||
|
if (currentAnimation != null) {
|
||||||
|
currentAnimation.cancel();
|
||||||
|
currentAnimation = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void openDrawer(boolean fast) {
|
||||||
|
if (AndroidUtilities.isTablet() && parentActionBarLayout != null && parentActionBarLayout.parentActivity != null) {
|
||||||
|
AndroidUtilities.hideKeyboard(parentActionBarLayout.parentActivity.getCurrentFocus());
|
||||||
|
}
|
||||||
|
cancelCurrentAnimation();
|
||||||
|
AnimatorSetProxy animatorSet = new AnimatorSetProxy();
|
||||||
|
animatorSet.playTogether(
|
||||||
|
ObjectAnimatorProxy.ofFloat(this, "drawerPosition", drawerLayout.getMeasuredWidth())
|
||||||
|
);
|
||||||
|
animatorSet.setInterpolator(new DecelerateInterpolator());
|
||||||
|
if (fast) {
|
||||||
|
animatorSet.setDuration(Math.max((int) (200.0f / drawerLayout.getMeasuredWidth() * (drawerLayout.getMeasuredWidth() - drawerPosition)), 50));
|
||||||
|
} else {
|
||||||
|
animatorSet.setDuration(300);
|
||||||
|
}
|
||||||
|
animatorSet.addListener(new AnimatorListenerAdapterProxy() {
|
||||||
|
@Override
|
||||||
|
public void onAnimationEnd(Object animator) {
|
||||||
|
onDrawerAnimationEnd(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAnimationCancel(Object animator) {
|
||||||
|
onDrawerAnimationEnd(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
animatorSet.start();
|
||||||
|
currentAnimation = animatorSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void closeDrawer(boolean fast) {
|
||||||
|
cancelCurrentAnimation();
|
||||||
|
AnimatorSetProxy animatorSet = new AnimatorSetProxy();
|
||||||
|
animatorSet.playTogether(
|
||||||
|
ObjectAnimatorProxy.ofFloat(this, "drawerPosition", 0)
|
||||||
|
);
|
||||||
|
animatorSet.setInterpolator(new DecelerateInterpolator());
|
||||||
|
if (fast) {
|
||||||
|
animatorSet.setDuration(Math.max((int) (200.0f / drawerLayout.getMeasuredWidth() * drawerPosition), 50));
|
||||||
|
} else {
|
||||||
|
animatorSet.setDuration(300);
|
||||||
|
}
|
||||||
|
animatorSet.addListener(new AnimatorListenerAdapterProxy() {
|
||||||
|
@Override
|
||||||
|
public void onAnimationEnd(Object animator) {
|
||||||
|
onDrawerAnimationEnd(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAnimationCancel(Object animator) {
|
||||||
|
onDrawerAnimationEnd(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
animatorSet.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onDrawerAnimationEnd(boolean opened) {
|
||||||
|
startedTracking = false;
|
||||||
|
currentAnimation = null;
|
||||||
|
drawerOpened = opened;
|
||||||
|
if (!opened) {
|
||||||
|
if (drawerLayout instanceof ListView) {
|
||||||
|
((ListView)drawerLayout).setSelectionFromTop(0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setScrimOpacity(float value) {
|
||||||
|
scrimOpacity = value;
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
private float getScrimOpacity() {
|
||||||
|
return scrimOpacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public View getDrawerLayout() {
|
||||||
|
return drawerLayout;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setParentActionBarLayout(ActionBarLayout layout) {
|
||||||
|
parentActionBarLayout = layout;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAllowOpenDrawer(boolean value) {
|
||||||
|
allowOpenDrawer = value;
|
||||||
|
if (!allowOpenDrawer && drawerPosition != 0) {
|
||||||
|
setDrawerPosition(0);
|
||||||
|
onDrawerAnimationEnd(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void prepareForDrawerOpen(MotionEvent ev) {
|
||||||
|
maybeStartTracking = false;
|
||||||
|
startedTracking = true;
|
||||||
|
if (ev != null) {
|
||||||
|
startedTrackingX = (int) ev.getX();
|
||||||
|
}
|
||||||
|
beginTrackingSent = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isDrawerOpened() {
|
||||||
|
return drawerOpened;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean onTouchEvent(MotionEvent ev) {
|
||||||
|
if (!parentActionBarLayout.checkTransitionAnimation()) {
|
||||||
|
if (drawerOpened && ev != null && ev.getX() > drawerPosition && !startedTracking) {
|
||||||
|
if (ev.getAction() == MotionEvent.ACTION_UP) {
|
||||||
|
closeDrawer(false);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (allowOpenDrawer && parentActionBarLayout.fragmentsStack.size() == 1) {
|
||||||
|
if (ev != null && (ev.getAction() == MotionEvent.ACTION_DOWN || ev.getAction() == MotionEvent.ACTION_MOVE) && !startedTracking && !maybeStartTracking) {
|
||||||
|
startedTrackingPointerId = ev.getPointerId(0);
|
||||||
|
maybeStartTracking = true;
|
||||||
|
startedTrackingX = (int) ev.getX();
|
||||||
|
startedTrackingY = (int) ev.getY();
|
||||||
|
cancelCurrentAnimation();
|
||||||
|
if (velocityTracker != null) {
|
||||||
|
velocityTracker.clear();
|
||||||
|
}
|
||||||
|
} else if (ev != null && ev.getAction() == MotionEvent.ACTION_MOVE && ev.getPointerId(0) == startedTrackingPointerId) {
|
||||||
|
if (velocityTracker == null) {
|
||||||
|
velocityTracker = VelocityTracker.obtain();
|
||||||
|
}
|
||||||
|
float dx = (int) (ev.getX() - startedTrackingX);
|
||||||
|
float dy = Math.abs((int) ev.getY() - startedTrackingY);
|
||||||
|
velocityTracker.addMovement(ev);
|
||||||
|
if (maybeStartTracking && !startedTracking && (dx > 0 && dx / 3.0f > Math.abs(dy) || dx < 0 && Math.abs(dx) >= Math.abs(dy) && Math.abs(dx) >= AndroidUtilities.dp(10))) {
|
||||||
|
prepareForDrawerOpen(ev);
|
||||||
|
startedTrackingX = (int) ev.getX();
|
||||||
|
requestDisallowInterceptTouchEvent(true);
|
||||||
|
} else if (startedTracking) {
|
||||||
|
if (!beginTrackingSent) {
|
||||||
|
if (((Activity)getContext()).getCurrentFocus() != null) {
|
||||||
|
AndroidUtilities.hideKeyboard(((Activity)getContext()).getCurrentFocus());
|
||||||
|
}
|
||||||
|
beginTrackingSent = true;
|
||||||
|
}
|
||||||
|
moveDrawerByX(dx);
|
||||||
|
startedTrackingX = (int) ev.getX();
|
||||||
|
}
|
||||||
|
} else if (ev == null || ev != null && ev.getPointerId(0) == startedTrackingPointerId && (ev.getAction() == MotionEvent.ACTION_CANCEL || ev.getAction() == MotionEvent.ACTION_UP || ev.getAction() == MotionEvent.ACTION_POINTER_UP)) {
|
||||||
|
if (velocityTracker == null) {
|
||||||
|
velocityTracker = VelocityTracker.obtain();
|
||||||
|
}
|
||||||
|
velocityTracker.computeCurrentVelocity(1000);
|
||||||
|
/*if (!startedTracking) {
|
||||||
|
float velX = velocityTracker.getXVelocity();
|
||||||
|
float velY = velocityTracker.getYVelocity();
|
||||||
|
if (Math.abs(velX) >= 3500 && Math.abs(velX) > Math.abs(velY)) {
|
||||||
|
prepareForDrawerOpen(ev);
|
||||||
|
if (!beginTrackingSent) {
|
||||||
|
if (((Activity)getContext()).getCurrentFocus() != null) {
|
||||||
|
AndroidUtilities.hideKeyboard(((Activity)getContext()).getCurrentFocus());
|
||||||
|
}
|
||||||
|
beginTrackingSent = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
if (startedTracking || drawerPosition != 0 && drawerPosition != drawerLayout.getMeasuredWidth()) {
|
||||||
|
float velX = velocityTracker.getXVelocity();
|
||||||
|
float velY = velocityTracker.getYVelocity();
|
||||||
|
boolean backAnimation = drawerPosition < drawerLayout.getMeasuredWidth() / 2.0f && (velX < 3500 || Math.abs(velX) < Math.abs(velY)) || velX < 0 && Math.abs(velX) >= 3500;
|
||||||
|
if (!backAnimation) {
|
||||||
|
openDrawer(!drawerOpened && Math.abs(velX) >= 3500);
|
||||||
|
} else {
|
||||||
|
closeDrawer(drawerOpened && Math.abs(velX) >= 3500);
|
||||||
|
}
|
||||||
|
startedTracking = false;
|
||||||
|
} else {
|
||||||
|
maybeStartTracking = false;
|
||||||
|
startedTracking = false;
|
||||||
|
}
|
||||||
|
if (velocityTracker != null) {
|
||||||
|
velocityTracker.recycle();
|
||||||
|
velocityTracker = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return startedTracking;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onInterceptTouchEvent(MotionEvent ev) {
|
||||||
|
return parentActionBarLayout.checkTransitionAnimation() || onTouchEvent(ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
|
||||||
|
if (maybeStartTracking && !startedTracking) {
|
||||||
|
onTouchEvent(null);
|
||||||
|
}
|
||||||
|
super.requestDisallowInterceptTouchEvent(disallowIntercept);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onLayout(boolean changed, int l, int t, int r, int b) {
|
||||||
|
inLayout = true;
|
||||||
|
final int width = r - l;
|
||||||
|
final int childCount = getChildCount();
|
||||||
|
for (int i = 0; i < childCount; i++) {
|
||||||
|
final View child = getChildAt(i);
|
||||||
|
|
||||||
|
if (child.getVisibility() == GONE) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
|
||||||
|
|
||||||
|
if (drawerLayout != child) {
|
||||||
|
child.layout(lp.leftMargin, lp.topMargin, lp.leftMargin + child.getMeasuredWidth(), lp.topMargin + child.getMeasuredHeight());
|
||||||
|
} else {
|
||||||
|
child.layout(-child.getMeasuredWidth() + (int)drawerPosition, lp.topMargin, (int)drawerPosition, lp.topMargin + child.getMeasuredHeight());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
inLayout = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void requestLayout() {
|
||||||
|
if (!inLayout) {
|
||||||
|
super.requestLayout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||||
|
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
|
||||||
|
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
|
||||||
|
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
|
||||||
|
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
|
||||||
|
|
||||||
|
setMeasuredDimension(widthSize, heightSize);
|
||||||
|
|
||||||
|
final boolean applyInsets = lastInsets != null && Build.VERSION.SDK_INT >= 21;
|
||||||
|
|
||||||
|
final int childCount = getChildCount();
|
||||||
|
for (int i = 0; i < childCount; i++) {
|
||||||
|
final View child = getChildAt(i);
|
||||||
|
|
||||||
|
if (child.getVisibility() == GONE) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
|
||||||
|
|
||||||
|
if (applyInsets) {
|
||||||
|
if (child.getFitsSystemWindows()) {
|
||||||
|
dispatchChildInsets(child, lastInsets, lp.gravity);
|
||||||
|
} else {
|
||||||
|
applyMarginInsets(lp, lastInsets, lp.gravity, Build.VERSION.SDK_INT >= 21);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (drawerLayout != child) {
|
||||||
|
final int contentWidthSpec = MeasureSpec.makeMeasureSpec(widthSize - lp.leftMargin - lp.rightMargin, MeasureSpec.EXACTLY);
|
||||||
|
final int contentHeightSpec = MeasureSpec.makeMeasureSpec(heightSize - lp.topMargin - lp.bottomMargin, MeasureSpec.EXACTLY);
|
||||||
|
child.measure(contentWidthSpec, contentHeightSpec);
|
||||||
|
} else {
|
||||||
|
child.setPadding(0, 0, 0, 0);
|
||||||
|
final int drawerWidthSpec = getChildMeasureSpec(widthMeasureSpec, minDrawerMargin + lp.leftMargin + lp.rightMargin, lp.width);
|
||||||
|
final int drawerHeightSpec = getChildMeasureSpec(heightMeasureSpec, lp.topMargin + lp.bottomMargin, lp.height);
|
||||||
|
child.measure(drawerWidthSpec, drawerHeightSpec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
|
||||||
|
final int height = getHeight();
|
||||||
|
final boolean drawingContent = child != drawerLayout;
|
||||||
|
int clipLeft = 0, clipRight = getWidth();
|
||||||
|
|
||||||
|
final int restoreCount = canvas.save();
|
||||||
|
if (drawingContent) {
|
||||||
|
final int childCount = getChildCount();
|
||||||
|
for (int i = 0; i < childCount; i++) {
|
||||||
|
final View v = getChildAt(i);
|
||||||
|
if (v == child || v.getVisibility() != VISIBLE || v != drawerLayout || v.getHeight() < height) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
final int vright = v.getRight();
|
||||||
|
if (vright > clipLeft) {
|
||||||
|
clipLeft = vright;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
canvas.clipRect(clipLeft, 0, clipRight, getHeight());
|
||||||
|
}
|
||||||
|
final boolean result = super.drawChild(canvas, child, drawingTime);
|
||||||
|
canvas.restoreToCount(restoreCount);
|
||||||
|
|
||||||
|
if (scrimOpacity > 0 && drawingContent) {
|
||||||
|
scrimPaint.setColor((int) (((0x99000000 & 0xff000000) >>> 24) * scrimOpacity) << 24);
|
||||||
|
canvas.drawRect(clipLeft, 0, clipRight, getHeight(), scrimPaint);
|
||||||
|
} else if (shadowLeft != null) {
|
||||||
|
final float alpha = Math.max(0, Math.min(drawerPosition / AndroidUtilities.dp(20), 1.0f));
|
||||||
|
if (alpha != 0) {
|
||||||
|
shadowLeft.setBounds((int)drawerPosition, child.getTop(), (int)drawerPosition + shadowLeft.getIntrinsicWidth(), child.getBottom());
|
||||||
|
shadowLeft.setAlpha((int) (0xff * alpha));
|
||||||
|
shadowLeft.draw(canvas);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,116 @@
|
|||||||
|
/*
|
||||||
|
* This is the source code of Telegram for Android v. 1.7.x.
|
||||||
|
* It is licensed under GNU GPL v. 2 or later.
|
||||||
|
* You should have received a copy of the license in this archive (see LICENSE).
|
||||||
|
*
|
||||||
|
* Copyright Nikolai Kudashov, 2013-2014.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.telegram.ui.ActionBar;
|
||||||
|
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.ColorFilter;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.view.animation.DecelerateInterpolator;
|
||||||
|
|
||||||
|
import org.telegram.android.AndroidUtilities;
|
||||||
|
|
||||||
|
public class MenuDrawable extends Drawable {
|
||||||
|
|
||||||
|
private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||||
|
private boolean reverseAngle = false;
|
||||||
|
private long lastFrameTime;
|
||||||
|
private boolean animationInProgress;
|
||||||
|
private float finalRotation;
|
||||||
|
private float currentRotation;
|
||||||
|
private int currentAnimationTime;
|
||||||
|
private DecelerateInterpolator interpolator = new DecelerateInterpolator();
|
||||||
|
|
||||||
|
public MenuDrawable() {
|
||||||
|
super();
|
||||||
|
paint.setColor(0xffffffff);
|
||||||
|
paint.setStrokeWidth(AndroidUtilities.dp(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRotation(float rotation, boolean animated) {
|
||||||
|
lastFrameTime = 0;
|
||||||
|
if (currentRotation == 1) {
|
||||||
|
reverseAngle = true;
|
||||||
|
} else if (currentRotation == 0) {
|
||||||
|
reverseAngle = false;
|
||||||
|
}
|
||||||
|
lastFrameTime = 0;
|
||||||
|
if (animated) {
|
||||||
|
if (currentRotation < rotation) {
|
||||||
|
currentAnimationTime = (int) (currentRotation * 300);
|
||||||
|
} else {
|
||||||
|
currentAnimationTime = (int) ((1.0f - currentRotation) * 300);
|
||||||
|
}
|
||||||
|
lastFrameTime = System.currentTimeMillis();
|
||||||
|
finalRotation = rotation;
|
||||||
|
} else {
|
||||||
|
finalRotation = currentRotation = rotation;
|
||||||
|
}
|
||||||
|
invalidateSelf();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void draw(Canvas canvas) {
|
||||||
|
if (currentRotation != finalRotation) {
|
||||||
|
if (lastFrameTime != 0) {
|
||||||
|
long dt = System.currentTimeMillis() - lastFrameTime;
|
||||||
|
|
||||||
|
currentAnimationTime += dt;
|
||||||
|
if (currentAnimationTime >= 300) {
|
||||||
|
currentRotation = finalRotation;
|
||||||
|
} else {
|
||||||
|
if (currentRotation < finalRotation) {
|
||||||
|
currentRotation = interpolator.getInterpolation(currentAnimationTime / 300.0f) * finalRotation;
|
||||||
|
} else {
|
||||||
|
currentRotation = 1.0f - interpolator.getInterpolation(currentAnimationTime / 300.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lastFrameTime = System.currentTimeMillis();
|
||||||
|
invalidateSelf();
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas.save();
|
||||||
|
canvas.translate(getIntrinsicWidth() / 2, getIntrinsicHeight() / 2);
|
||||||
|
canvas.rotate(currentRotation * (reverseAngle ? -180 : 180));
|
||||||
|
canvas.drawLine(-AndroidUtilities.dp(9), 0, AndroidUtilities.dp(9) - AndroidUtilities.dp(1) * currentRotation, 0, paint);
|
||||||
|
float endYDiff = AndroidUtilities.dp(5) * (1 - Math.abs(currentRotation)) - AndroidUtilities.dp(0.5f) * Math.abs(currentRotation);
|
||||||
|
float endXDiff = AndroidUtilities.dp(9) - AndroidUtilities.dp(0.5f) * Math.abs(currentRotation);
|
||||||
|
float startYDiff = AndroidUtilities.dp(5) + AndroidUtilities.dp(3.5f) * Math.abs(currentRotation);
|
||||||
|
float startXDiff = -AndroidUtilities.dp(9) + AndroidUtilities.dp(8.5f) * Math.abs(currentRotation);
|
||||||
|
canvas.drawLine(startXDiff, -startYDiff, endXDiff, -endYDiff, paint);
|
||||||
|
canvas.drawLine(startXDiff, startYDiff, endXDiff, endYDiff, paint);
|
||||||
|
canvas.restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setAlpha(int alpha) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setColorFilter(ColorFilter cf) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getOpacity() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getIntrinsicWidth() {
|
||||||
|
return AndroidUtilities.dp(24);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getIntrinsicHeight() {
|
||||||
|
return AndroidUtilities.dp(24);
|
||||||
|
}
|
||||||
|
}
|
@ -24,11 +24,11 @@ public class BaseContactsSearchAdapter extends BaseFragmentAdapter {
|
|||||||
protected String lastFoundUsername = null;
|
protected String lastFoundUsername = null;
|
||||||
|
|
||||||
public void queryServerSearch(final String query) {
|
public void queryServerSearch(final String query) {
|
||||||
|
if (reqId != 0) {
|
||||||
|
ConnectionsManager.getInstance().cancelRpc(reqId, true);
|
||||||
|
reqId = 0;
|
||||||
|
}
|
||||||
if (query == null || query.length() < 5) {
|
if (query == null || query.length() < 5) {
|
||||||
if (reqId != 0) {
|
|
||||||
ConnectionsManager.getInstance().cancelRpc(reqId, true);
|
|
||||||
reqId = 0;
|
|
||||||
}
|
|
||||||
globalSearch.clear();
|
globalSearch.clear();
|
||||||
lastReqId = 0;
|
lastReqId = 0;
|
||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
@ -41,7 +41,7 @@ public class BaseContactsSearchAdapter extends BaseFragmentAdapter {
|
|||||||
reqId = ConnectionsManager.getInstance().performRpc(req, new RPCRequest.RPCRequestDelegate() {
|
reqId = ConnectionsManager.getInstance().performRpc(req, new RPCRequest.RPCRequestDelegate() {
|
||||||
@Override
|
@Override
|
||||||
public void run(final TLObject response, final TLRPC.TL_error error) {
|
public void run(final TLObject response, final TLRPC.TL_error error) {
|
||||||
AndroidUtilities.RunOnUIThread(new Runnable() {
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (currentReqId == lastReqId) {
|
if (currentReqId == lastReqId) {
|
||||||
|
@ -15,12 +15,6 @@ import android.widget.BaseAdapter;
|
|||||||
|
|
||||||
public class BaseFragmentAdapter extends BaseAdapter {
|
public class BaseFragmentAdapter extends BaseAdapter {
|
||||||
|
|
||||||
public void onFragmentCreate() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onFragmentDestroy() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getCount() {
|
public int getCount() {
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -0,0 +1,152 @@
|
|||||||
|
/*
|
||||||
|
* This is the source code of Telegram for Android v. 1.7.x.
|
||||||
|
* It is licensed under GNU GPL v. 2 or later.
|
||||||
|
* You should have received a copy of the license in this archive (see LICENSE).
|
||||||
|
*
|
||||||
|
* Copyright Nikolai Kudashov, 2013-2014.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.telegram.ui.Adapters;
|
||||||
|
|
||||||
|
import android.util.SparseArray;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
|
public abstract class BaseSectionsAdapter extends BaseFragmentAdapter {
|
||||||
|
|
||||||
|
private SparseArray<Integer> sectionPositionCache;
|
||||||
|
private SparseArray<Integer> sectionCache;
|
||||||
|
private SparseArray<Integer> sectionCountCache;
|
||||||
|
private int sectionCount;
|
||||||
|
private int count;
|
||||||
|
|
||||||
|
private void cleanupCache() {
|
||||||
|
sectionCache = new SparseArray<Integer>();
|
||||||
|
sectionPositionCache = new SparseArray<Integer>();
|
||||||
|
sectionCountCache = new SparseArray<Integer>();
|
||||||
|
count = -1;
|
||||||
|
sectionCount = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BaseSectionsAdapter() {
|
||||||
|
super();
|
||||||
|
cleanupCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void notifyDataSetChanged() {
|
||||||
|
cleanupCache();
|
||||||
|
super.notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void notifyDataSetInvalidated() {
|
||||||
|
cleanupCache();
|
||||||
|
super.notifyDataSetInvalidated();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean areAllItemsEnabled() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEnabled(int position) {
|
||||||
|
return isRowEnabled(getSectionForPosition(position), getPositionInSectionForPosition(position));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final long getItemId(int position) {
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final int getCount() {
|
||||||
|
if (count >= 0) {
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
count = 0;
|
||||||
|
for (int i = 0; i < internalGetSectionCount(); i++) {
|
||||||
|
count += internalGetCountForSection(i);
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final Object getItem(int position) {
|
||||||
|
return getItem(getSectionForPosition(position), getPositionInSectionForPosition(position));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final int getItemViewType(int position) {
|
||||||
|
return getItemViewType(getSectionForPosition(position), getPositionInSectionForPosition(position));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final View getView(int position, View convertView, ViewGroup parent) {
|
||||||
|
return getItemView(getSectionForPosition(position), getPositionInSectionForPosition(position), convertView, parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int internalGetCountForSection(int section) {
|
||||||
|
Integer cachedSectionCount = sectionCountCache.get(section);
|
||||||
|
if (cachedSectionCount != null) {
|
||||||
|
return cachedSectionCount;
|
||||||
|
}
|
||||||
|
int sectionCount = getCountForSection(section);
|
||||||
|
sectionCountCache.put(section, sectionCount);
|
||||||
|
return sectionCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int internalGetSectionCount() {
|
||||||
|
if (sectionCount >= 0) {
|
||||||
|
return sectionCount;
|
||||||
|
}
|
||||||
|
sectionCount = getSectionCount();
|
||||||
|
return sectionCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final int getSectionForPosition(int position) {
|
||||||
|
Integer cachedSection = sectionCache.get(position);
|
||||||
|
if (cachedSection != null) {
|
||||||
|
return cachedSection;
|
||||||
|
}
|
||||||
|
int sectionStart = 0;
|
||||||
|
for (int i = 0; i < internalGetSectionCount(); i++) {
|
||||||
|
int sectionCount = internalGetCountForSection(i);
|
||||||
|
int sectionEnd = sectionStart + sectionCount;
|
||||||
|
if (position >= sectionStart && position < sectionEnd) {
|
||||||
|
sectionCache.put(position, i);
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
sectionStart = sectionEnd;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPositionInSectionForPosition(int position) {
|
||||||
|
Integer cachedPosition = sectionPositionCache.get(position);
|
||||||
|
if (cachedPosition != null) {
|
||||||
|
return cachedPosition;
|
||||||
|
}
|
||||||
|
int sectionStart = 0;
|
||||||
|
for (int i = 0; i < internalGetSectionCount(); i++) {
|
||||||
|
int sectionCount = internalGetCountForSection(i);
|
||||||
|
int sectionEnd = sectionStart + sectionCount;
|
||||||
|
if (position >= sectionStart && position < sectionEnd) {
|
||||||
|
int positionInSection = position - sectionStart;
|
||||||
|
sectionPositionCache.put(position, positionInSection);
|
||||||
|
return positionInSection;
|
||||||
|
}
|
||||||
|
sectionStart = sectionEnd;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract int getSectionCount();
|
||||||
|
public abstract int getCountForSection(int section);
|
||||||
|
public abstract boolean isRowEnabled(int section, int row);
|
||||||
|
public abstract int getItemViewType(int section, int position);
|
||||||
|
public abstract Object getItem(int section, int position);
|
||||||
|
public abstract View getItemView(int section, int position, View convertView, ViewGroup parent);
|
||||||
|
public abstract View getSectionHeaderView(int section, View convertView, ViewGroup parent);
|
||||||
|
}
|
@ -1,229 +0,0 @@
|
|||||||
/*
|
|
||||||
* This is the source code of Telegram for Android v. 1.3.x.
|
|
||||||
* It is licensed under GNU GPL v. 2 or later.
|
|
||||||
* You should have received a copy of the license in this archive (see LICENSE).
|
|
||||||
*
|
|
||||||
* Copyright Nikolai Kudashov, 2013-2014.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.telegram.ui.Adapters;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import org.telegram.android.LocaleController;
|
|
||||||
import org.telegram.messenger.TLRPC;
|
|
||||||
import org.telegram.android.ContactsController;
|
|
||||||
import org.telegram.android.MessagesController;
|
|
||||||
import org.telegram.messenger.R;
|
|
||||||
import org.telegram.ui.Cells.ChatOrUserCell;
|
|
||||||
import org.telegram.ui.Views.SectionedBaseAdapter;
|
|
||||||
import org.telegram.ui.Views.SettingsSectionLayout;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
|
||||||
|
|
||||||
public class ContactsActivityAdapter extends SectionedBaseAdapter {
|
|
||||||
private Context mContext;
|
|
||||||
private boolean onlyUsers;
|
|
||||||
private boolean usersAsSections;
|
|
||||||
private HashMap<Integer, TLRPC.User> ignoreUsers;
|
|
||||||
|
|
||||||
public ContactsActivityAdapter(Context context, boolean arg1, boolean arg2, HashMap<Integer, TLRPC.User> arg3) {
|
|
||||||
mContext = context;
|
|
||||||
onlyUsers = arg1;
|
|
||||||
usersAsSections = arg2;
|
|
||||||
ignoreUsers = arg3;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object getItem(int section, int position) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getItemId(int section, int position) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getSectionCount() {
|
|
||||||
int count = 0;
|
|
||||||
if (usersAsSections) {
|
|
||||||
count += ContactsController.getInstance().sortedUsersSectionsArray.size();
|
|
||||||
} else {
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
if (!onlyUsers) {
|
|
||||||
count += ContactsController.getInstance().sortedContactsSectionsArray.size();
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getCountForSection(int section) {
|
|
||||||
if (usersAsSections) {
|
|
||||||
if (section < ContactsController.getInstance().sortedUsersSectionsArray.size()) {
|
|
||||||
ArrayList<TLRPC.TL_contact> arr = ContactsController.getInstance().usersSectionsDict.get(ContactsController.getInstance().sortedUsersSectionsArray.get(section));
|
|
||||||
return arr.size();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (section == 0) {
|
|
||||||
return ContactsController.getInstance().contacts.size() + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ArrayList<ContactsController.Contact> arr = ContactsController.getInstance().contactsSectionsDict.get(ContactsController.getInstance().sortedContactsSectionsArray.get(section - 1));
|
|
||||||
return arr.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public View getItemView(int section, int position, View convertView, ViewGroup parent) {
|
|
||||||
|
|
||||||
TLRPC.User user = null;
|
|
||||||
int count = 0;
|
|
||||||
if (usersAsSections) {
|
|
||||||
if (section < ContactsController.getInstance().sortedUsersSectionsArray.size()) {
|
|
||||||
ArrayList<TLRPC.TL_contact> arr = ContactsController.getInstance().usersSectionsDict.get(ContactsController.getInstance().sortedUsersSectionsArray.get(section));
|
|
||||||
user = MessagesController.getInstance().getUser(arr.get(position).user_id);
|
|
||||||
count = arr.size();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (section == 0) {
|
|
||||||
if (position == 0) {
|
|
||||||
if (convertView == null) {
|
|
||||||
LayoutInflater li = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
|
||||||
convertView = li.inflate(R.layout.contacts_invite_row_layout, parent, false);
|
|
||||||
TextView textView = (TextView)convertView.findViewById(R.id.messages_list_row_name);
|
|
||||||
textView.setText(LocaleController.getString("InviteFriends", R.string.InviteFriends));
|
|
||||||
}
|
|
||||||
View divider = convertView.findViewById(R.id.settings_row_divider);
|
|
||||||
if (ContactsController.getInstance().contacts.isEmpty()) {
|
|
||||||
divider.setVisibility(View.INVISIBLE);
|
|
||||||
} else {
|
|
||||||
divider.setVisibility(View.VISIBLE);
|
|
||||||
}
|
|
||||||
return convertView;
|
|
||||||
}
|
|
||||||
user = MessagesController.getInstance().getUser(ContactsController.getInstance().contacts.get(position - 1).user_id);
|
|
||||||
count = ContactsController.getInstance().contacts.size();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (user != null) {
|
|
||||||
if (convertView == null) {
|
|
||||||
convertView = new ChatOrUserCell(mContext);
|
|
||||||
((ChatOrUserCell)convertView).usePadding = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
((ChatOrUserCell)convertView).setData(user, null, null, null, null);
|
|
||||||
|
|
||||||
if (ignoreUsers != null) {
|
|
||||||
if (ignoreUsers.containsKey(user.id)) {
|
|
||||||
((ChatOrUserCell)convertView).drawAlpha = 0.5f;
|
|
||||||
} else {
|
|
||||||
((ChatOrUserCell)convertView).drawAlpha = 1.0f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
((ChatOrUserCell) convertView).useSeparator = position != count - 1;
|
|
||||||
|
|
||||||
return convertView;
|
|
||||||
}
|
|
||||||
|
|
||||||
TextView textView;
|
|
||||||
if (convertView == null) {
|
|
||||||
LayoutInflater li = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
|
||||||
convertView = li.inflate(R.layout.settings_row_button_layout, parent, false);
|
|
||||||
textView = (TextView)convertView.findViewById(R.id.settings_row_text);
|
|
||||||
} else {
|
|
||||||
textView = (TextView)convertView.findViewById(R.id.settings_row_text);
|
|
||||||
}
|
|
||||||
|
|
||||||
View divider = convertView.findViewById(R.id.settings_row_divider);
|
|
||||||
ArrayList<ContactsController.Contact> arr = ContactsController.getInstance().contactsSectionsDict.get(ContactsController.getInstance().sortedContactsSectionsArray.get(section - 1));
|
|
||||||
ContactsController.Contact contact = arr.get(position);
|
|
||||||
if (divider != null) {
|
|
||||||
if (position == arr.size() - 1) {
|
|
||||||
divider.setVisibility(View.INVISIBLE);
|
|
||||||
} else {
|
|
||||||
divider.setVisibility(View.VISIBLE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (contact.first_name != null && contact.last_name != null) {
|
|
||||||
textView.setText(contact.first_name + " " + contact.last_name);
|
|
||||||
} else if (contact.first_name != null && contact.last_name == null) {
|
|
||||||
textView.setText(contact.first_name);
|
|
||||||
} else {
|
|
||||||
textView.setText(contact.last_name);
|
|
||||||
}
|
|
||||||
return convertView;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getItemViewType(int section, int position) {
|
|
||||||
if (usersAsSections) {
|
|
||||||
if (section < ContactsController.getInstance().sortedUsersSectionsArray.size()) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
} else if (section == 0) {
|
|
||||||
if (position == 0) {
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getItemViewTypeCount() {
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getSectionHeaderViewType(int section) {
|
|
||||||
if (usersAsSections) {
|
|
||||||
if (section < ContactsController.getInstance().sortedUsersSectionsArray.size()) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
} else if (section == 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getSectionHeaderViewTypeCount() {
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public View getSectionHeaderView(int section, View convertView, ViewGroup parent) {
|
|
||||||
if (usersAsSections) {
|
|
||||||
if (section < ContactsController.getInstance().sortedUsersSectionsArray.size()) {
|
|
||||||
if (convertView == null) {
|
|
||||||
convertView = new SettingsSectionLayout(mContext);
|
|
||||||
convertView.setBackgroundColor(0xffffffff);
|
|
||||||
}
|
|
||||||
((SettingsSectionLayout) convertView).setText(ContactsController.getInstance().sortedUsersSectionsArray.get(section));
|
|
||||||
return convertView;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (section == 0) {
|
|
||||||
if (convertView == null) {
|
|
||||||
LayoutInflater li = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
|
||||||
convertView = li.inflate(R.layout.empty_layout, parent, false);
|
|
||||||
}
|
|
||||||
return convertView;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (convertView == null) {
|
|
||||||
convertView = new SettingsSectionLayout(mContext);
|
|
||||||
convertView.setBackgroundColor(0xffffffff);
|
|
||||||
}
|
|
||||||
((SettingsSectionLayout) convertView).setText(ContactsController.getInstance().sortedContactsSectionsArray.get(section - 1));
|
|
||||||
return convertView;
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,271 @@
|
|||||||
|
/*
|
||||||
|
* This is the source code of Telegram for Android v. 1.3.x.
|
||||||
|
* It is licensed under GNU GPL v. 2 or later.
|
||||||
|
* You should have received a copy of the license in this archive (see LICENSE).
|
||||||
|
*
|
||||||
|
* Copyright Nikolai Kudashov, 2013-2014.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.telegram.ui.Adapters;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
|
import org.telegram.android.AndroidUtilities;
|
||||||
|
import org.telegram.android.LocaleController;
|
||||||
|
import org.telegram.messenger.TLRPC;
|
||||||
|
import org.telegram.android.ContactsController;
|
||||||
|
import org.telegram.android.MessagesController;
|
||||||
|
import org.telegram.messenger.R;
|
||||||
|
import org.telegram.ui.AnimationCompat.ViewProxy;
|
||||||
|
import org.telegram.ui.Cells.DividerCell;
|
||||||
|
import org.telegram.ui.Cells.GreySectionCell;
|
||||||
|
import org.telegram.ui.Cells.LetterSectionCell;
|
||||||
|
import org.telegram.ui.Cells.TextCell;
|
||||||
|
import org.telegram.ui.Cells.UserCell;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
public class ContactsAdapter extends BaseSectionsAdapter {
|
||||||
|
|
||||||
|
private Context mContext;
|
||||||
|
private boolean onlyUsers;
|
||||||
|
private boolean needPhonebook;
|
||||||
|
private HashMap<Integer, TLRPC.User> ignoreUsers;
|
||||||
|
private HashMap<Integer, ?> checkedMap;
|
||||||
|
private boolean scrolling;
|
||||||
|
|
||||||
|
public ContactsAdapter(Context context, boolean arg1, boolean arg2, HashMap<Integer, TLRPC.User> arg3) {
|
||||||
|
mContext = context;
|
||||||
|
onlyUsers = arg1;
|
||||||
|
needPhonebook = arg2;
|
||||||
|
ignoreUsers = arg3;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCheckedMap(HashMap<Integer, ?> map) {
|
||||||
|
checkedMap = map;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIsScrolling(boolean value) {
|
||||||
|
scrolling = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getItem(int section, int position) {
|
||||||
|
if (onlyUsers) {
|
||||||
|
if (section < ContactsController.getInstance().sortedUsersSectionsArray.size()) {
|
||||||
|
ArrayList<TLRPC.TL_contact> arr = ContactsController.getInstance().usersSectionsDict.get(ContactsController.getInstance().sortedUsersSectionsArray.get(section));
|
||||||
|
if (position < arr.size()) {
|
||||||
|
return MessagesController.getInstance().getUser(arr.get(position).user_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
if (section == 0) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
if (section - 1 < ContactsController.getInstance().sortedUsersSectionsArray.size()) {
|
||||||
|
ArrayList<TLRPC.TL_contact> arr = ContactsController.getInstance().usersSectionsDict.get(ContactsController.getInstance().sortedUsersSectionsArray.get(section - 1));
|
||||||
|
if (position < arr.size()) {
|
||||||
|
return MessagesController.getInstance().getUser(arr.get(position).user_id);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (needPhonebook) {
|
||||||
|
return ContactsController.getInstance().phoneBookContacts.get(position);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isRowEnabled(int section, int row) {
|
||||||
|
if (onlyUsers) {
|
||||||
|
ArrayList<TLRPC.TL_contact> arr = ContactsController.getInstance().usersSectionsDict.get(ContactsController.getInstance().sortedUsersSectionsArray.get(section));
|
||||||
|
return row < arr.size();
|
||||||
|
} else {
|
||||||
|
if (section == 0) {
|
||||||
|
if (needPhonebook) {
|
||||||
|
if (row == 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (row == 3) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else if (section - 1 < ContactsController.getInstance().sortedUsersSectionsArray.size()) {
|
||||||
|
ArrayList<TLRPC.TL_contact> arr = ContactsController.getInstance().usersSectionsDict.get(ContactsController.getInstance().sortedUsersSectionsArray.get(section - 1));
|
||||||
|
return row < arr.size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSectionCount() {
|
||||||
|
int count = ContactsController.getInstance().sortedUsersSectionsArray.size();
|
||||||
|
if (!onlyUsers) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
if (needPhonebook) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getCountForSection(int section) {
|
||||||
|
if (onlyUsers) {
|
||||||
|
if (section < ContactsController.getInstance().sortedUsersSectionsArray.size()) {
|
||||||
|
ArrayList<TLRPC.TL_contact> arr = ContactsController.getInstance().usersSectionsDict.get(ContactsController.getInstance().sortedUsersSectionsArray.get(section));
|
||||||
|
int count = arr.size();
|
||||||
|
if (section != (ContactsController.getInstance().sortedUsersSectionsArray.size() - 1) || needPhonebook) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (section == 0) {
|
||||||
|
if (needPhonebook) {
|
||||||
|
return 2;
|
||||||
|
} else {
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
} else if (section - 1 < ContactsController.getInstance().sortedUsersSectionsArray.size()) {
|
||||||
|
ArrayList<TLRPC.TL_contact> arr = ContactsController.getInstance().usersSectionsDict.get(ContactsController.getInstance().sortedUsersSectionsArray.get(section - 1));
|
||||||
|
int count = arr.size();
|
||||||
|
if (section - 1 != (ContactsController.getInstance().sortedUsersSectionsArray.size() - 1) || needPhonebook) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (needPhonebook) {
|
||||||
|
return ContactsController.getInstance().phoneBookContacts.size();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View getSectionHeaderView(int section, View convertView, ViewGroup parent) {
|
||||||
|
if (convertView == null) {
|
||||||
|
convertView = new LetterSectionCell(mContext);
|
||||||
|
}
|
||||||
|
if (onlyUsers) {
|
||||||
|
if (section < ContactsController.getInstance().sortedUsersSectionsArray.size()) {
|
||||||
|
((LetterSectionCell) convertView).setLetter(ContactsController.getInstance().sortedUsersSectionsArray.get(section));
|
||||||
|
} else {
|
||||||
|
((LetterSectionCell) convertView).setLetter("");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (section == 0) {
|
||||||
|
((LetterSectionCell) convertView).setLetter("");
|
||||||
|
} else if (section - 1 < ContactsController.getInstance().sortedUsersSectionsArray.size()) {
|
||||||
|
((LetterSectionCell) convertView).setLetter(ContactsController.getInstance().sortedUsersSectionsArray.get(section - 1));
|
||||||
|
} else {
|
||||||
|
((LetterSectionCell) convertView).setLetter("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return convertView;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View getItemView(int section, int position, View convertView, ViewGroup parent) {
|
||||||
|
int type = getItemViewType(section, position);
|
||||||
|
if (type == 4) {
|
||||||
|
if (convertView == null) {
|
||||||
|
convertView = new DividerCell(mContext);
|
||||||
|
convertView.setPadding(AndroidUtilities.dp(LocaleController.isRTL ? 28 : 72), 0, AndroidUtilities.dp(LocaleController.isRTL ? 72 : 28), 0);
|
||||||
|
}
|
||||||
|
} else if (type == 3) {
|
||||||
|
if (convertView == null) {
|
||||||
|
convertView = new GreySectionCell(mContext);
|
||||||
|
((GreySectionCell) convertView).setText(LocaleController.getString("Contacts", R.string.Contacts).toUpperCase());
|
||||||
|
}
|
||||||
|
} else if (type == 2) {
|
||||||
|
if (convertView == null) {
|
||||||
|
convertView = new TextCell(mContext);
|
||||||
|
}
|
||||||
|
TextCell actionCell = (TextCell) convertView;
|
||||||
|
if (needPhonebook) {
|
||||||
|
actionCell.setTextAndIcon(LocaleController.getString("InviteFriends", R.string.InviteFriends), R.drawable.menu_invite);
|
||||||
|
} else {
|
||||||
|
if (position == 0) {
|
||||||
|
actionCell.setTextAndIcon(LocaleController.getString("NewGroup", R.string.NewGroup), R.drawable.menu_newgroup);
|
||||||
|
} else if (position == 1) {
|
||||||
|
actionCell.setTextAndIcon(LocaleController.getString("NewSecretChat", R.string.NewSecretChat), R.drawable.menu_secret);
|
||||||
|
} else if (position == 2) {
|
||||||
|
actionCell.setTextAndIcon(LocaleController.getString("NewBroadcastList", R.string.NewBroadcastList), R.drawable.menu_broadcast);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (type == 1) {
|
||||||
|
if (convertView == null) {
|
||||||
|
convertView = new TextCell(mContext);
|
||||||
|
}
|
||||||
|
ContactsController.Contact contact = ContactsController.getInstance().phoneBookContacts.get(position);
|
||||||
|
if (contact.first_name != null && contact.last_name != null) {
|
||||||
|
((TextCell) convertView).setText(contact.first_name + " " + contact.last_name);
|
||||||
|
} else if (contact.first_name != null && contact.last_name == null) {
|
||||||
|
((TextCell) convertView).setText(contact.first_name);
|
||||||
|
} else {
|
||||||
|
((TextCell) convertView).setText(contact.last_name);
|
||||||
|
}
|
||||||
|
} else if (type == 0) {
|
||||||
|
if (convertView == null) {
|
||||||
|
convertView = new UserCell(mContext, 58);
|
||||||
|
((UserCell) convertView).setStatusColors(0xffa8a8a8, 0xff3b84c0);
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayList<TLRPC.TL_contact> arr = ContactsController.getInstance().usersSectionsDict.get(ContactsController.getInstance().sortedUsersSectionsArray.get(section - (onlyUsers ? 0 : 1)));
|
||||||
|
TLRPC.User user = MessagesController.getInstance().getUser(arr.get(position).user_id);
|
||||||
|
((UserCell)convertView).setData(user, null, null, 0);
|
||||||
|
if (checkedMap != null) {
|
||||||
|
((UserCell) convertView).setChecked(checkedMap.containsKey(user.id), !scrolling && Build.VERSION.SDK_INT > 10);
|
||||||
|
}
|
||||||
|
if (ignoreUsers != null) {
|
||||||
|
if (ignoreUsers.containsKey(user.id)) {
|
||||||
|
ViewProxy.setAlpha(convertView, 0.5f);
|
||||||
|
} else {
|
||||||
|
ViewProxy.setAlpha(convertView, 1.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return convertView;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemViewType(int section, int position) {
|
||||||
|
if (onlyUsers) {
|
||||||
|
ArrayList<TLRPC.TL_contact> arr = ContactsController.getInstance().usersSectionsDict.get(ContactsController.getInstance().sortedUsersSectionsArray.get(section));
|
||||||
|
return position < arr.size() ? 0 : 4;
|
||||||
|
} else {
|
||||||
|
if (section == 0) {
|
||||||
|
if (needPhonebook) {
|
||||||
|
if (position == 1) {
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (position == 3) {
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 2;
|
||||||
|
} else if (section - 1 < ContactsController.getInstance().sortedUsersSectionsArray.size()) {
|
||||||
|
ArrayList<TLRPC.TL_contact> arr = ContactsController.getInstance().usersSectionsDict.get(ContactsController.getInstance().sortedUsersSectionsArray.get(section - 1));
|
||||||
|
return position < arr.size() ? 0 : 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getViewTypeCount() {
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
}
|
@ -22,29 +22,47 @@ import org.telegram.messenger.FileLog;
|
|||||||
import org.telegram.android.MessagesController;
|
import org.telegram.android.MessagesController;
|
||||||
import org.telegram.messenger.UserConfig;
|
import org.telegram.messenger.UserConfig;
|
||||||
import org.telegram.messenger.Utilities;
|
import org.telegram.messenger.Utilities;
|
||||||
import org.telegram.ui.Cells.ChatOrUserCell;
|
import org.telegram.ui.Cells.GreySectionCell;
|
||||||
import org.telegram.ui.Views.SettingsSectionLayout;
|
import org.telegram.ui.Cells.ProfileSearchCell;
|
||||||
|
import org.telegram.ui.Cells.UserCell;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Timer;
|
import java.util.Timer;
|
||||||
import java.util.TimerTask;
|
import java.util.TimerTask;
|
||||||
|
|
||||||
public class ContactsActivitySearchAdapter extends BaseContactsSearchAdapter {
|
public class ContactsSearchAdapter extends BaseContactsSearchAdapter {
|
||||||
private Context mContext;
|
private Context mContext;
|
||||||
private HashMap<Integer, TLRPC.User> ignoreUsers;
|
private HashMap<Integer, TLRPC.User> ignoreUsers;
|
||||||
private ArrayList<TLRPC.User> searchResult;
|
private ArrayList<TLRPC.User> searchResult = new ArrayList<TLRPC.User>();
|
||||||
private ArrayList<CharSequence> searchResultNames;
|
private ArrayList<CharSequence> searchResultNames = new ArrayList<CharSequence>();
|
||||||
|
private HashMap<Integer, ?> checkedMap;
|
||||||
private Timer searchTimer;
|
private Timer searchTimer;
|
||||||
private boolean allowUsernameSearch;
|
private boolean allowUsernameSearch;
|
||||||
|
private boolean useUserCell;
|
||||||
|
|
||||||
public ContactsActivitySearchAdapter(Context context, HashMap<Integer, TLRPC.User> arg1, boolean usernameSearch) {
|
public ContactsSearchAdapter(Context context, HashMap<Integer, TLRPC.User> arg1, boolean usernameSearch) {
|
||||||
mContext = context;
|
mContext = context;
|
||||||
ignoreUsers = arg1;
|
ignoreUsers = arg1;
|
||||||
allowUsernameSearch = usernameSearch;
|
allowUsernameSearch = usernameSearch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setCheckedMap(HashMap<Integer, ?> map) {
|
||||||
|
checkedMap = map;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUseUserCell(boolean value) {
|
||||||
|
useUserCell = value;
|
||||||
|
}
|
||||||
|
|
||||||
public void searchDialogs(final String query) {
|
public void searchDialogs(final String query) {
|
||||||
|
try {
|
||||||
|
if (searchTimer != null) {
|
||||||
|
searchTimer.cancel();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
FileLog.e("tmessages", e);
|
||||||
|
}
|
||||||
if (query == null) {
|
if (query == null) {
|
||||||
searchResult.clear();
|
searchResult.clear();
|
||||||
searchResultNames.clear();
|
searchResultNames.clear();
|
||||||
@ -53,13 +71,6 @@ public class ContactsActivitySearchAdapter extends BaseContactsSearchAdapter {
|
|||||||
}
|
}
|
||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
} else {
|
} else {
|
||||||
try {
|
|
||||||
if (searchTimer != null) {
|
|
||||||
searchTimer.cancel();
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
FileLog.e("tmessages", e);
|
|
||||||
}
|
|
||||||
searchTimer = new Timer();
|
searchTimer = new Timer();
|
||||||
searchTimer.schedule(new TimerTask() {
|
searchTimer.schedule(new TimerTask() {
|
||||||
@Override
|
@Override
|
||||||
@ -77,7 +88,7 @@ public class ContactsActivitySearchAdapter extends BaseContactsSearchAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void processSearch(final String query) {
|
private void processSearch(final String query) {
|
||||||
AndroidUtilities.RunOnUIThread(new Runnable() {
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (allowUsernameSearch) {
|
if (allowUsernameSearch) {
|
||||||
@ -130,7 +141,7 @@ public class ContactsActivitySearchAdapter extends BaseContactsSearchAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void updateSearchResults(final ArrayList<TLRPC.User> users, final ArrayList<CharSequence> names) {
|
private void updateSearchResults(final ArrayList<TLRPC.User> users, final ArrayList<CharSequence> names) {
|
||||||
AndroidUtilities.RunOnUIThread(new Runnable() {
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
searchResult = users;
|
searchResult = users;
|
||||||
@ -197,16 +208,21 @@ public class ContactsActivitySearchAdapter extends BaseContactsSearchAdapter {
|
|||||||
public View getView(int i, View view, ViewGroup viewGroup) {
|
public View getView(int i, View view, ViewGroup viewGroup) {
|
||||||
if (i == searchResult.size()) {
|
if (i == searchResult.size()) {
|
||||||
if (view == null) {
|
if (view == null) {
|
||||||
view = new SettingsSectionLayout(mContext);
|
view = new GreySectionCell(mContext);
|
||||||
((SettingsSectionLayout) view).setText(LocaleController.getString("GlobalSearch", R.string.GlobalSearch));
|
((GreySectionCell) view).setText(LocaleController.getString("GlobalSearch", R.string.GlobalSearch));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (view == null) {
|
if (view == null) {
|
||||||
view = new ChatOrUserCell(mContext);
|
if (useUserCell) {
|
||||||
((ChatOrUserCell) view).usePadding = false;
|
view = new UserCell(mContext, 1);
|
||||||
|
if (checkedMap != null) {
|
||||||
|
((UserCell) view).setChecked(false, false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
view = new ProfileSearchCell(mContext);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
((ChatOrUserCell) view).useSeparator = (i != getCount() - 1 && i != searchResult.size() - 1);
|
|
||||||
TLRPC.User user = getItem(i);
|
TLRPC.User user = getItem(i);
|
||||||
if (user != null) {
|
if (user != null) {
|
||||||
CharSequence username = null;
|
CharSequence username = null;
|
||||||
@ -221,20 +237,27 @@ public class ContactsActivitySearchAdapter extends BaseContactsSearchAdapter {
|
|||||||
}
|
}
|
||||||
} else if (i > searchResult.size() && user.username != null) {
|
} else if (i > searchResult.size() && user.username != null) {
|
||||||
try {
|
try {
|
||||||
username = Html.fromHtml(String.format("<font color=\"#357aa8\">@%s</font>%s", user.username.substring(0, lastFoundUsername.length()), user.username.substring(lastFoundUsername.length())));
|
username = Html.fromHtml(String.format("<font color=\"#4d83b3\">@%s</font>%s", user.username.substring(0, lastFoundUsername.length()), user.username.substring(lastFoundUsername.length())));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
username = user.username;
|
username = user.username;
|
||||||
FileLog.e("tmessages", e);
|
FileLog.e("tmessages", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
((ChatOrUserCell) view).setData(user, null, null, name, username);
|
if (useUserCell) {
|
||||||
|
((UserCell) view).setData(user, name, username, 0);
|
||||||
if (ignoreUsers != null) {
|
if (checkedMap != null) {
|
||||||
if (ignoreUsers.containsKey(user.id)) {
|
((UserCell) view).setChecked(checkedMap.containsKey(user.id), false);
|
||||||
((ChatOrUserCell) view).drawAlpha = 0.5f;
|
}
|
||||||
} else {
|
} else {
|
||||||
((ChatOrUserCell) view).drawAlpha = 1.0f;
|
((ProfileSearchCell) view).setData(user, null, null, name, username);
|
||||||
|
((ProfileSearchCell) view).useSeparator = (i != getCount() - 1 && i != searchResult.size() - 1);
|
||||||
|
if (ignoreUsers != null) {
|
||||||
|
if (ignoreUsers.containsKey(user.id)) {
|
||||||
|
((ProfileSearchCell) view).drawAlpha = 0.5f;
|
||||||
|
} else {
|
||||||
|
((ProfileSearchCell) view).drawAlpha = 1.0f;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,165 @@
|
|||||||
|
/*
|
||||||
|
* This is the source code of Telegram for Android v. 1.7.x.
|
||||||
|
* It is licensed under GNU GPL v. 2 or later.
|
||||||
|
* You should have received a copy of the license in this archive (see LICENSE).
|
||||||
|
*
|
||||||
|
* Copyright Nikolai Kudashov, 2013-2014.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.telegram.ui.Adapters;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
|
import org.telegram.android.AndroidUtilities;
|
||||||
|
import org.telegram.android.LocaleController;
|
||||||
|
import org.telegram.messenger.FileLog;
|
||||||
|
import org.telegram.messenger.ApplicationLoader;
|
||||||
|
import org.telegram.ui.Cells.DividerCell;
|
||||||
|
import org.telegram.ui.Cells.LetterSectionCell;
|
||||||
|
import org.telegram.ui.Cells.TextSettingsCell;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
public class CountryAdapter extends BaseSectionsAdapter {
|
||||||
|
|
||||||
|
public static class Country {
|
||||||
|
public String name;
|
||||||
|
public String code;
|
||||||
|
public String shortname;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Context mContext;
|
||||||
|
private HashMap<String, ArrayList<Country>> countries = new HashMap<String, ArrayList<Country>>();
|
||||||
|
private ArrayList<String> sortedCountries = new ArrayList<String>();
|
||||||
|
|
||||||
|
public CountryAdapter(Context context) {
|
||||||
|
mContext = context;
|
||||||
|
|
||||||
|
try {
|
||||||
|
InputStream stream = ApplicationLoader.applicationContext.getResources().getAssets().open("countries.txt");
|
||||||
|
BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
|
||||||
|
String line;
|
||||||
|
while ((line = reader.readLine()) != null) {
|
||||||
|
String[] args = line.split(";");
|
||||||
|
Country c = new Country();
|
||||||
|
c.name = args[2];
|
||||||
|
c.code = args[0];
|
||||||
|
c.shortname = args[1];
|
||||||
|
String n = c.name.substring(0, 1).toUpperCase();
|
||||||
|
ArrayList<Country> arr = countries.get(n);
|
||||||
|
if (arr == null) {
|
||||||
|
arr = new ArrayList<Country>();
|
||||||
|
countries.put(n, arr);
|
||||||
|
sortedCountries.add(n);
|
||||||
|
}
|
||||||
|
arr.add(c);
|
||||||
|
}
|
||||||
|
reader.close();
|
||||||
|
stream.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
FileLog.e("tmessages", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
Collections.sort(sortedCountries, new Comparator<String>() {
|
||||||
|
@Override
|
||||||
|
public int compare(String lhs, String rhs) {
|
||||||
|
return lhs.compareTo(rhs);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
for (ArrayList<Country> arr : countries.values()) {
|
||||||
|
Collections.sort(arr, new Comparator<Country>() {
|
||||||
|
@Override
|
||||||
|
public int compare(Country country, Country country2) {
|
||||||
|
return country.name.compareTo(country2.name);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public HashMap<String, ArrayList<Country>> getCountries() {
|
||||||
|
return countries;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Country getItem(int section, int position) {
|
||||||
|
if (section < 0 || section >= sortedCountries.size()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
ArrayList<Country> arr = countries.get(sortedCountries.get(section));
|
||||||
|
if (position < 0 || position >= arr.size()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return arr.get(position);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isRowEnabled(int section, int row) {
|
||||||
|
ArrayList<Country> arr = countries.get(sortedCountries.get(section));
|
||||||
|
return row < arr.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSectionCount() {
|
||||||
|
return sortedCountries.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getCountForSection(int section) {
|
||||||
|
int count = countries.get(sortedCountries.get(section)).size();
|
||||||
|
if (section != sortedCountries.size() - 1) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View getSectionHeaderView(int section, View convertView, ViewGroup parent) {
|
||||||
|
if (convertView == null) {
|
||||||
|
convertView = new LetterSectionCell(mContext);
|
||||||
|
((LetterSectionCell) convertView).setCellHeight(AndroidUtilities.dp(48));
|
||||||
|
}
|
||||||
|
((LetterSectionCell) convertView).setLetter(sortedCountries.get(section).toUpperCase());
|
||||||
|
return convertView;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View getItemView(int section, int position, View convertView, ViewGroup parent) {
|
||||||
|
int type = getItemViewType(section, position);
|
||||||
|
if (type == 1) {
|
||||||
|
if (convertView == null) {
|
||||||
|
convertView = new DividerCell(mContext);
|
||||||
|
convertView.setPadding(AndroidUtilities.dp(LocaleController.isRTL ? 24 : 72), 0, AndroidUtilities.dp(LocaleController.isRTL ? 72 : 24), 0);
|
||||||
|
}
|
||||||
|
} else if (type == 0) {
|
||||||
|
if (convertView == null) {
|
||||||
|
convertView = new TextSettingsCell(mContext);
|
||||||
|
convertView.setPadding(AndroidUtilities.dp(LocaleController.isRTL ? 16 : 54), 0, AndroidUtilities.dp(LocaleController.isRTL ? 54 : 16), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayList<Country> arr = countries.get(sortedCountries.get(section));
|
||||||
|
Country c = arr.get(position);
|
||||||
|
((TextSettingsCell) convertView).setTextAndValue(c.name, "+" + c.code, false);
|
||||||
|
}
|
||||||
|
return convertView;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemViewType(int section, int position) {
|
||||||
|
ArrayList<Country> arr = countries.get(sortedCountries.get(section));
|
||||||
|
return position < arr.size() ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getViewTypeCount() {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,165 @@
|
|||||||
|
/*
|
||||||
|
* This is the source code of Telegram for Android v. 1.7.x.
|
||||||
|
* It is licensed under GNU GPL v. 2 or later.
|
||||||
|
* You should have received a copy of the license in this archive (see LICENSE).
|
||||||
|
*
|
||||||
|
* Copyright Nikolai Kudashov, 2013-2014.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.telegram.ui.Adapters;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
|
import org.telegram.android.AndroidUtilities;
|
||||||
|
import org.telegram.messenger.FileLog;
|
||||||
|
import org.telegram.messenger.Utilities;
|
||||||
|
import org.telegram.ui.Adapters.CountryAdapter.Country;
|
||||||
|
import org.telegram.ui.Cells.TextSettingsCell;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Timer;
|
||||||
|
import java.util.TimerTask;
|
||||||
|
|
||||||
|
public class CountrySearchAdapter extends BaseFragmentAdapter {
|
||||||
|
|
||||||
|
private Context mContext;
|
||||||
|
private Timer searchTimer;
|
||||||
|
private ArrayList<CountryAdapter.Country> searchResult;
|
||||||
|
private HashMap<String, ArrayList<Country>> countries;
|
||||||
|
|
||||||
|
public CountrySearchAdapter(Context context, HashMap<String, ArrayList<Country>> countries) {
|
||||||
|
mContext = context;
|
||||||
|
this.countries = countries;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void search(final String query) {
|
||||||
|
if (query == null) {
|
||||||
|
searchResult = null;
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
if (searchTimer != null) {
|
||||||
|
searchTimer.cancel();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
FileLog.e("tmessages", e);
|
||||||
|
}
|
||||||
|
searchTimer = new Timer();
|
||||||
|
searchTimer.schedule(new TimerTask() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
searchTimer.cancel();
|
||||||
|
searchTimer = null;
|
||||||
|
} catch (Exception e) {
|
||||||
|
FileLog.e("tmessages", e);
|
||||||
|
}
|
||||||
|
processSearch(query);
|
||||||
|
}
|
||||||
|
}, 100, 300);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processSearch(final String query) {
|
||||||
|
Utilities.searchQueue.postRunnable(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
|
||||||
|
String q = query.trim().toLowerCase();
|
||||||
|
if (q.length() == 0) {
|
||||||
|
updateSearchResults(new ArrayList<Country>());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
long time = System.currentTimeMillis();
|
||||||
|
ArrayList<Country> resultArray = new ArrayList<Country>();
|
||||||
|
|
||||||
|
String n = query.substring(0, 1);
|
||||||
|
ArrayList<Country> arr = countries.get(n.toUpperCase());
|
||||||
|
if (arr != null) {
|
||||||
|
for (Country c : arr) {
|
||||||
|
if (c.name.toLowerCase().startsWith(query)) {
|
||||||
|
resultArray.add(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateSearchResults(resultArray);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateSearchResults(final ArrayList<Country> arrCounties) {
|
||||||
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
searchResult = arrCounties;
|
||||||
|
notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean areAllItemsEnabled() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEnabled(int i) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getCount() {
|
||||||
|
if (searchResult == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return searchResult.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Country getItem(int i) {
|
||||||
|
if (i < 0 || i >= searchResult.size()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return searchResult.get(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getItemId(int i) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasStableIds() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View getView(int i, View view, ViewGroup viewGroup) {
|
||||||
|
if (view == null) {
|
||||||
|
view = new TextSettingsCell(mContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
Country c = searchResult.get(i);
|
||||||
|
((TextSettingsCell) view).setTextAndValue(c.name, "+" + c.code, i != searchResult.size() - 1);
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemViewType(int i) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getViewTypeCount() {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return searchResult == null || searchResult.size() == 0;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,153 @@
|
|||||||
|
/*
|
||||||
|
* This is the source code of Telegram for Android v. 1.7.x.
|
||||||
|
* It is licensed under GNU GPL v. 2 or later.
|
||||||
|
* You should have received a copy of the license in this archive (see LICENSE).
|
||||||
|
*
|
||||||
|
* Copyright Nikolai Kudashov, 2013-2014.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.telegram.ui.Adapters;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
|
import org.telegram.android.AndroidUtilities;
|
||||||
|
import org.telegram.android.MessageObject;
|
||||||
|
import org.telegram.android.MessagesController;
|
||||||
|
import org.telegram.messenger.TLRPC;
|
||||||
|
import org.telegram.ui.Cells.DialogCell;
|
||||||
|
import org.telegram.ui.Cells.LoadingCell;
|
||||||
|
|
||||||
|
public class DialogsAdapter extends BaseFragmentAdapter {
|
||||||
|
|
||||||
|
private Context mContext;
|
||||||
|
private boolean serverOnly;
|
||||||
|
private long openedDialogId;
|
||||||
|
|
||||||
|
public DialogsAdapter(Context context, boolean onlyFromServer) {
|
||||||
|
mContext = context;
|
||||||
|
serverOnly = onlyFromServer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOpenedDialogId(long id) {
|
||||||
|
openedDialogId = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean areAllItemsEnabled() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEnabled(int i) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getCount() {
|
||||||
|
int count;
|
||||||
|
if (serverOnly) {
|
||||||
|
count = MessagesController.getInstance().dialogsServerOnly.size();
|
||||||
|
} else {
|
||||||
|
count = MessagesController.getInstance().dialogs.size();
|
||||||
|
}
|
||||||
|
if (count == 0 && MessagesController.getInstance().loadingDialogs) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (!MessagesController.getInstance().dialogsEndReached) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TLRPC.TL_dialog getItem(int i) {
|
||||||
|
if (serverOnly) {
|
||||||
|
if (i < 0 || i >= MessagesController.getInstance().dialogsServerOnly.size()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return MessagesController.getInstance().dialogsServerOnly.get(i);
|
||||||
|
} else {
|
||||||
|
if (i < 0 || i >= MessagesController.getInstance().dialogs.size()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return MessagesController.getInstance().dialogs.get(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getItemId(int i) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasStableIds() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View getView(int i, View view, ViewGroup viewGroup) {
|
||||||
|
int type = getItemViewType(i);
|
||||||
|
if (type == 1) {
|
||||||
|
if (view == null) {
|
||||||
|
view = new LoadingCell(mContext);
|
||||||
|
}
|
||||||
|
} else if (type == 0) {
|
||||||
|
if (view == null) {
|
||||||
|
view = new DialogCell(mContext);
|
||||||
|
}
|
||||||
|
((DialogCell) view).useSeparator = (i != getCount() - 1);
|
||||||
|
TLRPC.TL_dialog dialog = null;
|
||||||
|
if (serverOnly) {
|
||||||
|
dialog = MessagesController.getInstance().dialogsServerOnly.get(i);
|
||||||
|
} else {
|
||||||
|
dialog = MessagesController.getInstance().dialogs.get(i);
|
||||||
|
if (AndroidUtilities.isTablet()) {
|
||||||
|
if (dialog.id == openedDialogId) {
|
||||||
|
view.setBackgroundColor(0x0f000000);
|
||||||
|
} else {
|
||||||
|
view.setBackgroundColor(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MessageObject message = MessagesController.getInstance().dialogMessage.get(dialog.top_message);
|
||||||
|
((DialogCell) view).setDialog(dialog.id, message, true, dialog.last_message_date, dialog.unread_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemViewType(int i) {
|
||||||
|
if (serverOnly && i == MessagesController.getInstance().dialogsServerOnly.size() || !serverOnly && i == MessagesController.getInstance().dialogs.size()) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getViewTypeCount() {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEmpty() {
|
||||||
|
if (MessagesController.getInstance().loadingDialogs && MessagesController.getInstance().dialogs.isEmpty()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
int count;
|
||||||
|
if (serverOnly) {
|
||||||
|
count = MessagesController.getInstance().dialogsServerOnly.size();
|
||||||
|
} else {
|
||||||
|
count = MessagesController.getInstance().dialogs.size();
|
||||||
|
}
|
||||||
|
if (count == 0 && MessagesController.getInstance().loadingDialogs) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!MessagesController.getInstance().dialogsEndReached) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
return count == 0;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,631 @@
|
|||||||
|
/*
|
||||||
|
* This is the source code of Telegram for Android v. 1.7.x.
|
||||||
|
* It is licensed under GNU GPL v. 2 or later.
|
||||||
|
* You should have received a copy of the license in this archive (see LICENSE).
|
||||||
|
*
|
||||||
|
* Copyright Nikolai Kudashov, 2013-2014.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.telegram.ui.Adapters;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.text.Html;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
|
import org.telegram.SQLite.SQLiteCursor;
|
||||||
|
import org.telegram.android.AndroidUtilities;
|
||||||
|
import org.telegram.android.ContactsController;
|
||||||
|
import org.telegram.android.LocaleController;
|
||||||
|
import org.telegram.android.MessageObject;
|
||||||
|
import org.telegram.android.MessagesController;
|
||||||
|
import org.telegram.android.MessagesStorage;
|
||||||
|
import org.telegram.messenger.ByteBufferDesc;
|
||||||
|
import org.telegram.messenger.ConnectionsManager;
|
||||||
|
import org.telegram.messenger.FileLog;
|
||||||
|
import org.telegram.messenger.R;
|
||||||
|
import org.telegram.messenger.RPCRequest;
|
||||||
|
import org.telegram.messenger.TLClassStore;
|
||||||
|
import org.telegram.messenger.TLObject;
|
||||||
|
import org.telegram.messenger.TLRPC;
|
||||||
|
import org.telegram.messenger.UserConfig;
|
||||||
|
import org.telegram.messenger.Utilities;
|
||||||
|
import org.telegram.ui.Cells.DialogCell;
|
||||||
|
import org.telegram.ui.Cells.GreySectionCell;
|
||||||
|
import org.telegram.ui.Cells.LoadingCell;
|
||||||
|
import org.telegram.ui.Cells.ProfileSearchCell;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Timer;
|
||||||
|
import java.util.TimerTask;
|
||||||
|
|
||||||
|
public class DialogsSearchAdapter extends BaseContactsSearchAdapter {
|
||||||
|
|
||||||
|
private Context mContext;
|
||||||
|
private Timer searchTimer;
|
||||||
|
private ArrayList<TLObject> searchResult = new ArrayList<TLObject>();
|
||||||
|
private ArrayList<CharSequence> searchResultNames = new ArrayList<CharSequence>();
|
||||||
|
private ArrayList<MessageObject> searchResultMessages = new ArrayList<MessageObject>();
|
||||||
|
private String lastSearchText;
|
||||||
|
private long reqId = 0;
|
||||||
|
private int lastReqId;
|
||||||
|
private MessagesActivitySearchAdapterDelegate delegate;
|
||||||
|
private boolean needMessagesSearch;
|
||||||
|
private boolean messagesSearchEndReached;
|
||||||
|
private String lastMessagesSearchString;
|
||||||
|
private int lastSearchId = 0;
|
||||||
|
|
||||||
|
private class DialogSearchResult {
|
||||||
|
public TLObject object;
|
||||||
|
public int date;
|
||||||
|
public CharSequence name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static interface MessagesActivitySearchAdapterDelegate {
|
||||||
|
public abstract void searchStateChanged(boolean searching);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DialogsSearchAdapter(Context context, boolean messagesSearch) {
|
||||||
|
mContext = context;
|
||||||
|
needMessagesSearch = messagesSearch;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDelegate(MessagesActivitySearchAdapterDelegate delegate) {
|
||||||
|
this.delegate = delegate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isMessagesSearchEndReached() {
|
||||||
|
return messagesSearchEndReached;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void loadMoreSearchMessages() {
|
||||||
|
searchMessagesInternal(lastMessagesSearchString);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void searchMessagesInternal(final String query) {
|
||||||
|
if (!needMessagesSearch) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (reqId != 0) {
|
||||||
|
ConnectionsManager.getInstance().cancelRpc(reqId, true);
|
||||||
|
reqId = 0;
|
||||||
|
}
|
||||||
|
if (query == null || query.length() == 0) {
|
||||||
|
searchResultMessages.clear();
|
||||||
|
lastReqId = 0;
|
||||||
|
lastMessagesSearchString = null;
|
||||||
|
notifyDataSetChanged();
|
||||||
|
if (delegate != null) {
|
||||||
|
delegate.searchStateChanged(false);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final TLRPC.TL_messages_search req = new TLRPC.TL_messages_search();
|
||||||
|
req.limit = 20;
|
||||||
|
req.peer = new TLRPC.TL_inputPeerEmpty();
|
||||||
|
req.q = query;
|
||||||
|
if (lastMessagesSearchString != null && query.equals(lastMessagesSearchString) && !searchResultMessages.isEmpty()) {
|
||||||
|
req.max_id = searchResultMessages.get(searchResultMessages.size() - 1).messageOwner.id;
|
||||||
|
}
|
||||||
|
lastMessagesSearchString = query;
|
||||||
|
req.filter = new TLRPC.TL_inputMessagesFilterEmpty();
|
||||||
|
final int currentReqId = ++lastReqId;
|
||||||
|
if (delegate != null) {
|
||||||
|
delegate.searchStateChanged(true);
|
||||||
|
}
|
||||||
|
reqId = ConnectionsManager.getInstance().performRpc(req, new RPCRequest.RPCRequestDelegate() {
|
||||||
|
@Override
|
||||||
|
public void run(final TLObject response, final TLRPC.TL_error error) {
|
||||||
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (currentReqId == lastReqId) {
|
||||||
|
if (error == null) {
|
||||||
|
TLRPC.messages_Messages res = (TLRPC.messages_Messages) response;
|
||||||
|
MessagesStorage.getInstance().putUsersAndChats(res.users, res.chats, true, true);
|
||||||
|
MessagesController.getInstance().putUsers(res.users, false);
|
||||||
|
MessagesController.getInstance().putChats(res.chats, false);
|
||||||
|
if (req.max_id == 0) {
|
||||||
|
searchResultMessages.clear();
|
||||||
|
}
|
||||||
|
for (TLRPC.Message message : res.messages) {
|
||||||
|
searchResultMessages.add(new MessageObject(message, null, 0));
|
||||||
|
}
|
||||||
|
messagesSearchEndReached = res.messages.size() != 20;
|
||||||
|
notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (delegate != null) {
|
||||||
|
delegate.searchStateChanged(false);
|
||||||
|
}
|
||||||
|
reqId = 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, true, RPCRequest.RPCRequestClassGeneric | RPCRequest.RPCRequestClassFailOnServerErrors);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void searchDialogsInternal(final String query, final boolean serverOnly, final int searchId) {
|
||||||
|
MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
String q = query.trim().toLowerCase();
|
||||||
|
if (q.length() == 0) {
|
||||||
|
lastSearchId = -1;
|
||||||
|
updateSearchResults(new ArrayList<TLObject>(), new ArrayList<CharSequence>(), new ArrayList<TLRPC.User>(), lastSearchId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayList<Integer> usersToLoad = new ArrayList<Integer>();
|
||||||
|
ArrayList<Integer> chatsToLoad = new ArrayList<Integer>();
|
||||||
|
ArrayList<Integer> encryptedToLoad = new ArrayList<Integer>();
|
||||||
|
ArrayList<TLRPC.User> encUsers = new ArrayList<TLRPC.User>();
|
||||||
|
int resultCount = 0;
|
||||||
|
|
||||||
|
HashMap<Long, DialogSearchResult> dialogsResult = new HashMap<Long, DialogSearchResult>();
|
||||||
|
SQLiteCursor cursor = MessagesStorage.getInstance().getDatabase().queryFinalized(String.format(Locale.US, "SELECT did, date FROM dialogs ORDER BY date DESC LIMIT 200"));
|
||||||
|
while (cursor.next()) {
|
||||||
|
long id = cursor.longValue(0);
|
||||||
|
DialogSearchResult dialogSearchResult = new DialogSearchResult();
|
||||||
|
dialogSearchResult.date = cursor.intValue(1);
|
||||||
|
dialogsResult.put(id, dialogSearchResult);
|
||||||
|
|
||||||
|
int lower_id = (int)id;
|
||||||
|
int high_id = (int)(id >> 32);
|
||||||
|
if (lower_id != 0) {
|
||||||
|
if (high_id == 1) {
|
||||||
|
if (!serverOnly && !chatsToLoad.contains(lower_id)) {
|
||||||
|
chatsToLoad.add(lower_id);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (lower_id > 0) {
|
||||||
|
if (!usersToLoad.contains(lower_id)) {
|
||||||
|
usersToLoad.add(lower_id);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!chatsToLoad.contains(-lower_id)) {
|
||||||
|
chatsToLoad.add(-lower_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (!serverOnly) {
|
||||||
|
if (!encryptedToLoad.contains(high_id)) {
|
||||||
|
encryptedToLoad.add(high_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cursor.dispose();
|
||||||
|
|
||||||
|
if (!usersToLoad.isEmpty()) {
|
||||||
|
cursor = MessagesStorage.getInstance().getDatabase().queryFinalized(String.format(Locale.US, "SELECT data, status, name FROM users WHERE uid IN(%s)", TextUtils.join(",", usersToLoad)));
|
||||||
|
while (cursor.next()) {
|
||||||
|
String name = cursor.stringValue(2);
|
||||||
|
String username = null;
|
||||||
|
int usernamePos = name.lastIndexOf(";;;");
|
||||||
|
if (usernamePos != -1) {
|
||||||
|
username = name.substring(usernamePos + 3);
|
||||||
|
}
|
||||||
|
int found = 0;
|
||||||
|
if (name.startsWith(q) || name.contains(" " + q)) {
|
||||||
|
found = 1;
|
||||||
|
} else if (username != null && username.startsWith(q)) {
|
||||||
|
found = 2;
|
||||||
|
}
|
||||||
|
if (found != 0) {
|
||||||
|
ByteBufferDesc data = MessagesStorage.getInstance().getBuffersStorage().getFreeBuffer(cursor.byteArrayLength(0));
|
||||||
|
if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) {
|
||||||
|
TLRPC.User user = (TLRPC.User) TLClassStore.Instance().TLdeserialize(data, data.readInt32());
|
||||||
|
if (user.id != UserConfig.getClientUserId()) {
|
||||||
|
DialogSearchResult dialogSearchResult = dialogsResult.get((long)user.id);
|
||||||
|
if (user.status != null) {
|
||||||
|
user.status.expires = cursor.intValue(1);
|
||||||
|
}
|
||||||
|
if (found == 1) {
|
||||||
|
dialogSearchResult.name = Utilities.generateSearchName(user.first_name, user.last_name, q);
|
||||||
|
} else {
|
||||||
|
dialogSearchResult.name = Utilities.generateSearchName("@" + user.username, null, "@" + q);
|
||||||
|
}
|
||||||
|
dialogSearchResult.object = user;
|
||||||
|
resultCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MessagesStorage.getInstance().getBuffersStorage().reuseFreeBuffer(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cursor.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!chatsToLoad.isEmpty()) {
|
||||||
|
cursor = MessagesStorage.getInstance().getDatabase().queryFinalized(String.format(Locale.US, "SELECT data, name FROM chats WHERE uid IN(%s)", TextUtils.join(",", chatsToLoad)));
|
||||||
|
while (cursor.next()) {
|
||||||
|
String name = cursor.stringValue(1);
|
||||||
|
String[] args = name.split(" ");
|
||||||
|
if (name.startsWith(q) || name.contains(" " + q)) {
|
||||||
|
ByteBufferDesc data = MessagesStorage.getInstance().getBuffersStorage().getFreeBuffer(cursor.byteArrayLength(0));
|
||||||
|
if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) {
|
||||||
|
TLRPC.Chat chat = (TLRPC.Chat) TLClassStore.Instance().TLdeserialize(data, data.readInt32());
|
||||||
|
long dialog_id;
|
||||||
|
if (chat.id > 0) {
|
||||||
|
dialog_id = -chat.id;
|
||||||
|
} else {
|
||||||
|
dialog_id = AndroidUtilities.makeBroadcastId(chat.id);
|
||||||
|
}
|
||||||
|
DialogSearchResult dialogSearchResult = dialogsResult.get(dialog_id);
|
||||||
|
dialogSearchResult.name = Utilities.generateSearchName(chat.title, null, q);
|
||||||
|
dialogSearchResult.object = chat;
|
||||||
|
resultCount++;
|
||||||
|
}
|
||||||
|
MessagesStorage.getInstance().getBuffersStorage().reuseFreeBuffer(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cursor.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!encryptedToLoad.isEmpty()) {
|
||||||
|
cursor = MessagesStorage.getInstance().getDatabase().queryFinalized(String.format(Locale.US, "SELECT q.data, u.name, q.user, q.g, q.authkey, q.ttl, u.data, u.status, q.layer, q.seq_in, q.seq_out, q.use_count, q.exchange_id, q.key_date, q.fprint, q.fauthkey, q.khash FROM enc_chats as q INNER JOIN users as u ON q.user = u.uid WHERE q.uid IN(%s)", TextUtils.join(",", encryptedToLoad)));
|
||||||
|
while (cursor.next()) {
|
||||||
|
String name = cursor.stringValue(1);
|
||||||
|
|
||||||
|
String username = null;
|
||||||
|
int usernamePos = name.lastIndexOf(";;;");
|
||||||
|
if (usernamePos != -1) {
|
||||||
|
username = name.substring(usernamePos + 2);
|
||||||
|
}
|
||||||
|
int found = 0;
|
||||||
|
if (name.startsWith(q) || name.contains(" " + q)) {
|
||||||
|
found = 1;
|
||||||
|
} else if (username != null && username.startsWith(q)) {
|
||||||
|
found = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (found != 0) {
|
||||||
|
ByteBufferDesc data = MessagesStorage.getInstance().getBuffersStorage().getFreeBuffer(cursor.byteArrayLength(0));
|
||||||
|
ByteBufferDesc data2 = MessagesStorage.getInstance().getBuffersStorage().getFreeBuffer(cursor.byteArrayLength(6));
|
||||||
|
if (data != null && cursor.byteBufferValue(0, data.buffer) != 0 && cursor.byteBufferValue(6, data2.buffer) != 0) {
|
||||||
|
TLRPC.EncryptedChat chat = (TLRPC.EncryptedChat) TLClassStore.Instance().TLdeserialize(data, data.readInt32());
|
||||||
|
DialogSearchResult dialogSearchResult = dialogsResult.get((long)chat.id << 32);
|
||||||
|
|
||||||
|
chat.user_id = cursor.intValue(2);
|
||||||
|
chat.a_or_b = cursor.byteArrayValue(3);
|
||||||
|
chat.auth_key = cursor.byteArrayValue(4);
|
||||||
|
chat.ttl = cursor.intValue(5);
|
||||||
|
chat.layer = cursor.intValue(8);
|
||||||
|
chat.seq_in = cursor.intValue(9);
|
||||||
|
chat.seq_out = cursor.intValue(10);
|
||||||
|
int use_count = cursor.intValue(11);
|
||||||
|
chat.key_use_count_in = (short)(use_count >> 16);
|
||||||
|
chat.key_use_count_out = (short)(use_count);
|
||||||
|
chat.exchange_id = cursor.longValue(12);
|
||||||
|
chat.key_create_date = cursor.intValue(13);
|
||||||
|
chat.future_key_fingerprint = cursor.longValue(14);
|
||||||
|
chat.future_auth_key = cursor.byteArrayValue(15);
|
||||||
|
chat.key_hash = cursor.byteArrayValue(16);
|
||||||
|
|
||||||
|
TLRPC.User user = (TLRPC.User)TLClassStore.Instance().TLdeserialize(data2, data2.readInt32());
|
||||||
|
if (user.status != null) {
|
||||||
|
user.status.expires = cursor.intValue(7);
|
||||||
|
}
|
||||||
|
if (found == 1) {
|
||||||
|
dialogSearchResult.name = Html.fromHtml("<font color=\"#00a60e\">" + ContactsController.formatName(user.first_name, user.last_name) + "</font>");
|
||||||
|
} else {
|
||||||
|
dialogSearchResult.name = Utilities.generateSearchName("@" + user.username, null, "@" + q);
|
||||||
|
}
|
||||||
|
dialogSearchResult.object = chat;
|
||||||
|
encUsers.add(user);
|
||||||
|
resultCount++;
|
||||||
|
}
|
||||||
|
MessagesStorage.getInstance().getBuffersStorage().reuseFreeBuffer(data);
|
||||||
|
MessagesStorage.getInstance().getBuffersStorage().reuseFreeBuffer(data2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cursor.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayList<DialogSearchResult> searchResults = new ArrayList<DialogSearchResult>(resultCount);
|
||||||
|
for (DialogSearchResult dialogSearchResult : dialogsResult.values()) {
|
||||||
|
if (dialogSearchResult.object != null && dialogSearchResult.name != null) {
|
||||||
|
searchResults.add(dialogSearchResult);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Collections.sort(searchResults, new Comparator<DialogSearchResult>() {
|
||||||
|
@Override
|
||||||
|
public int compare(DialogSearchResult lhs, DialogSearchResult rhs) {
|
||||||
|
if (lhs.date < rhs.date) {
|
||||||
|
return 1;
|
||||||
|
} else if (lhs.date > rhs.date) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ArrayList<TLObject> resultArray = new ArrayList<TLObject>();
|
||||||
|
ArrayList<CharSequence> resultArrayNames = new ArrayList<CharSequence>();
|
||||||
|
|
||||||
|
for (DialogSearchResult dialogSearchResult : searchResults) {
|
||||||
|
resultArray.add(dialogSearchResult.object);
|
||||||
|
resultArrayNames.add(dialogSearchResult.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor = MessagesStorage.getInstance().getDatabase().queryFinalized("SELECT u.data, u.status, u.name, u.uid FROM users as u INNER JOIN contacts as c ON u.uid = c.uid");
|
||||||
|
while (cursor.next()) {
|
||||||
|
int uid = cursor.intValue(3);
|
||||||
|
if (dialogsResult.containsKey((long)uid)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String name = cursor.stringValue(2);
|
||||||
|
String username = null;
|
||||||
|
int usernamePos = name.lastIndexOf(";;;");
|
||||||
|
if (usernamePos != -1) {
|
||||||
|
username = name.substring(usernamePos + 3);
|
||||||
|
}
|
||||||
|
int found = 0;
|
||||||
|
if (name.startsWith(q) || name.contains(" " + q)) {
|
||||||
|
found = 1;
|
||||||
|
} else if (username != null && username.startsWith(q)) {
|
||||||
|
found = 2;
|
||||||
|
}
|
||||||
|
if (found != 0) {
|
||||||
|
ByteBufferDesc data = MessagesStorage.getInstance().getBuffersStorage().getFreeBuffer(cursor.byteArrayLength(0));
|
||||||
|
if (data != null && cursor.byteBufferValue(0, data.buffer) != 0) {
|
||||||
|
TLRPC.User user = (TLRPC.User) TLClassStore.Instance().TLdeserialize(data, data.readInt32());
|
||||||
|
if (user.id != UserConfig.getClientUserId()) {
|
||||||
|
if (user.status != null) {
|
||||||
|
user.status.expires = cursor.intValue(1);
|
||||||
|
}
|
||||||
|
if (found == 1) {
|
||||||
|
resultArrayNames.add(Utilities.generateSearchName(user.first_name, user.last_name, q));
|
||||||
|
} else {
|
||||||
|
resultArrayNames.add(Utilities.generateSearchName("@" + user.username, null, "@" + q));
|
||||||
|
}
|
||||||
|
resultArray.add(user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MessagesStorage.getInstance().getBuffersStorage().reuseFreeBuffer(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cursor.dispose();
|
||||||
|
|
||||||
|
updateSearchResults(resultArray, resultArrayNames, encUsers, searchId);
|
||||||
|
} catch (Exception e) {
|
||||||
|
FileLog.e("tmessages", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateSearchResults(final ArrayList<TLObject> result, final ArrayList<CharSequence> names, final ArrayList<TLRPC.User> encUsers, final int searchId) {
|
||||||
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (searchId != lastSearchId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (TLObject obj : result) {
|
||||||
|
if (obj instanceof TLRPC.User) {
|
||||||
|
TLRPC.User user = (TLRPC.User) obj;
|
||||||
|
MessagesController.getInstance().putUser(user, true);
|
||||||
|
} else if (obj instanceof TLRPC.Chat) {
|
||||||
|
TLRPC.Chat chat = (TLRPC.Chat) obj;
|
||||||
|
MessagesController.getInstance().putChat(chat, true);
|
||||||
|
} else if (obj instanceof TLRPC.EncryptedChat) {
|
||||||
|
TLRPC.EncryptedChat chat = (TLRPC.EncryptedChat) obj;
|
||||||
|
MessagesController.getInstance().putEncryptedChat(chat, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (TLRPC.User user : encUsers) {
|
||||||
|
MessagesController.getInstance().putUser(user, true);
|
||||||
|
}
|
||||||
|
searchResult = result;
|
||||||
|
searchResultNames = names;
|
||||||
|
notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLastSearchText() {
|
||||||
|
return lastSearchText;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isGlobalSearch(int i) {
|
||||||
|
return i > searchResult.size() && i <= globalSearch.size() + searchResult.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void searchDialogs(final String query, final boolean serverOnly) {
|
||||||
|
if (query != null && lastSearchText != null && query.equals(lastSearchText)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if (searchTimer != null) {
|
||||||
|
searchTimer.cancel();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
FileLog.e("tmessages", e);
|
||||||
|
}
|
||||||
|
if (query == null || query.length() == 0) {
|
||||||
|
searchResult.clear();
|
||||||
|
searchResultNames.clear();
|
||||||
|
searchMessagesInternal(null);
|
||||||
|
queryServerSearch(null);
|
||||||
|
notifyDataSetChanged();
|
||||||
|
} else {
|
||||||
|
final int searchId = ++lastSearchId;
|
||||||
|
searchTimer = new Timer();
|
||||||
|
searchTimer.schedule(new TimerTask() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
searchTimer.cancel();
|
||||||
|
searchTimer = null;
|
||||||
|
} catch (Exception e) {
|
||||||
|
FileLog.e("tmessages", e);
|
||||||
|
}
|
||||||
|
searchDialogsInternal(query, serverOnly, searchId);
|
||||||
|
AndroidUtilities.runOnUIThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
queryServerSearch(query);
|
||||||
|
searchMessagesInternal(query);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, 200, 300);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean areAllItemsEnabled() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEnabled(int i) {
|
||||||
|
return i != searchResult.size() && i != searchResult.size() + (globalSearch.isEmpty() ? 0 : globalSearch.size() + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getCount() {
|
||||||
|
int count = searchResult.size();
|
||||||
|
int globalCount = globalSearch.size();
|
||||||
|
int messagesCount = searchResultMessages.size();
|
||||||
|
if (globalCount != 0) {
|
||||||
|
count += globalCount + 1;
|
||||||
|
}
|
||||||
|
if (messagesCount != 0) {
|
||||||
|
count += messagesCount + 1 + (messagesSearchEndReached ? 0 : 1);
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getItem(int i) {
|
||||||
|
int localCount = searchResult.size();
|
||||||
|
int globalCount = globalSearch.isEmpty() ? 0 : globalSearch.size() + 1;
|
||||||
|
int messagesCount = searchResultMessages.isEmpty() ? 0 : searchResultMessages.size() + 1;
|
||||||
|
if (i >= 0 && i < localCount) {
|
||||||
|
return searchResult.get(i);
|
||||||
|
} else if (i > localCount && i < globalCount + localCount) {
|
||||||
|
return globalSearch.get(i - localCount - 1);
|
||||||
|
} else if (i > globalCount + localCount && i < globalCount + localCount + messagesCount) {
|
||||||
|
return searchResultMessages.get(i - localCount - globalCount - 1);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getItemId(int i) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasStableIds() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View getView(int i, View view, ViewGroup viewGroup) {
|
||||||
|
int type = getItemViewType(i);
|
||||||
|
|
||||||
|
if (type == 1) {
|
||||||
|
if (view == null) {
|
||||||
|
view = new GreySectionCell(mContext);
|
||||||
|
}
|
||||||
|
if (!globalSearch.isEmpty() && i == searchResult.size()) {
|
||||||
|
((GreySectionCell) view).setText(LocaleController.getString("GlobalSearch", R.string.GlobalSearch));
|
||||||
|
} else {
|
||||||
|
((GreySectionCell) view).setText(LocaleController.getString("SearchMessages", R.string.SearchMessages));
|
||||||
|
}
|
||||||
|
} else if (type == 0) {
|
||||||
|
if (view == null) {
|
||||||
|
view = new ProfileSearchCell(mContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
TLRPC.User user = null;
|
||||||
|
TLRPC.Chat chat = null;
|
||||||
|
TLRPC.EncryptedChat encryptedChat = null;
|
||||||
|
|
||||||
|
int localCount = searchResult.size();
|
||||||
|
int globalCount = globalSearch.isEmpty() ? 0 : globalSearch.size() + 1;
|
||||||
|
|
||||||
|
((ProfileSearchCell) view).useSeparator = (i != getCount() - 1 && i != localCount - 1 && i != localCount + globalCount - 1);
|
||||||
|
Object obj = getItem(i);
|
||||||
|
if (obj instanceof TLRPC.User) {
|
||||||
|
user = MessagesController.getInstance().getUser(((TLRPC.User) obj).id);
|
||||||
|
if (user == null) {
|
||||||
|
user = (TLRPC.User) obj;
|
||||||
|
}
|
||||||
|
} else if (obj instanceof TLRPC.Chat) {
|
||||||
|
chat = MessagesController.getInstance().getChat(((TLRPC.Chat) obj).id);
|
||||||
|
} else if (obj instanceof TLRPC.EncryptedChat) {
|
||||||
|
encryptedChat = MessagesController.getInstance().getEncryptedChat(((TLRPC.EncryptedChat) obj).id);
|
||||||
|
user = MessagesController.getInstance().getUser(encryptedChat.user_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
CharSequence username = null;
|
||||||
|
CharSequence name = null;
|
||||||
|
if (i < searchResult.size()) {
|
||||||
|
name = searchResultNames.get(i);
|
||||||
|
if (name != null && user != null && user.username != null && user.username.length() > 0) {
|
||||||
|
if (name.toString().startsWith("@" + user.username)) {
|
||||||
|
username = name;
|
||||||
|
name = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (i > searchResult.size() && user != null && user.username != null) {
|
||||||
|
try {
|
||||||
|
username = Html.fromHtml(String.format("<font color=\"#4d83b3\">@%s</font>%s", user.username.substring(0, lastFoundUsername.length()), user.username.substring(lastFoundUsername.length())));
|
||||||
|
} catch (Exception e) {
|
||||||
|
username = user.username;
|
||||||
|
FileLog.e("tmessages", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
((ProfileSearchCell) view).setData(user, chat, encryptedChat, name, username);
|
||||||
|
} else if (type == 2) {
|
||||||
|
if (view == null) {
|
||||||
|
view = new DialogCell(mContext);
|
||||||
|
}
|
||||||
|
((DialogCell) view).useSeparator = (i != getCount() - 1);
|
||||||
|
MessageObject messageObject = (MessageObject)getItem(i);
|
||||||
|
((DialogCell) view).setDialog(messageObject.getDialogId(), messageObject, false, messageObject.messageOwner.date, 0);
|
||||||
|
} else if (type == 3) {
|
||||||
|
if (view == null) {
|
||||||
|
view = new LoadingCell(mContext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemViewType(int i) {
|
||||||
|
int localCount = searchResult.size();
|
||||||
|
int globalCount = globalSearch.isEmpty() ? 0 : globalSearch.size() + 1;
|
||||||
|
int messagesCount = searchResultMessages.isEmpty() ? 0 : searchResultMessages.size() + 1;
|
||||||
|
if (i >= 0 && i < localCount || i > localCount && i < globalCount + localCount) {
|
||||||
|
return 0;
|
||||||
|
} else if (i > globalCount + localCount && i < globalCount + localCount + messagesCount) {
|
||||||
|
return 2;
|
||||||
|
} else if (messagesCount != 0 && i == globalCount + localCount + messagesCount) {
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getViewTypeCount() {
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return searchResult.isEmpty() && globalSearch.isEmpty() && searchResultMessages.isEmpty();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,125 @@
|
|||||||
|
/*
|
||||||
|
* This is the source code of Telegram for Android v. 1.7.x.
|
||||||
|
* It is licensed under GNU GPL v. 2 or later.
|
||||||
|
* You should have received a copy of the license in this archive (see LICENSE).
|
||||||
|
*
|
||||||
|
* Copyright Nikolai Kudashov, 2013-2014.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.telegram.ui.Adapters;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.BaseAdapter;
|
||||||
|
|
||||||
|
import org.telegram.android.LocaleController;
|
||||||
|
import org.telegram.android.MessagesController;
|
||||||
|
import org.telegram.messenger.R;
|
||||||
|
import org.telegram.messenger.UserConfig;
|
||||||
|
import org.telegram.ui.Cells.DrawerActionCell;
|
||||||
|
import org.telegram.ui.Cells.DividerCell;
|
||||||
|
import org.telegram.ui.Cells.EmptyCell;
|
||||||
|
import org.telegram.ui.Cells.DrawerProfileCell;
|
||||||
|
|
||||||
|
public class DrawerLayoutAdapter extends BaseAdapter {
|
||||||
|
|
||||||
|
private Context mContext;
|
||||||
|
|
||||||
|
public DrawerLayoutAdapter(Context context) {
|
||||||
|
mContext = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean areAllItemsEnabled() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEnabled(int i) {
|
||||||
|
return !(i == 0 || i == 1 || i == 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getCount() {
|
||||||
|
return UserConfig.isClientActivated() ? 10 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getItem(int i) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getItemId(int i) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasStableIds() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View getView(int i, View view, ViewGroup viewGroup) {
|
||||||
|
int type = getItemViewType(i);
|
||||||
|
if (type == 0) {
|
||||||
|
if (view == null) {
|
||||||
|
view = new DrawerProfileCell(mContext);
|
||||||
|
}
|
||||||
|
((DrawerProfileCell) view).setUser(MessagesController.getInstance().getUser(UserConfig.getClientUserId()));
|
||||||
|
} else if (type == 1) {
|
||||||
|
if (view == null) {
|
||||||
|
view = new EmptyCell(mContext, 8);
|
||||||
|
}
|
||||||
|
} else if (type == 2) {
|
||||||
|
if (view == null) {
|
||||||
|
view = new DividerCell(mContext);
|
||||||
|
}
|
||||||
|
} else if (type == 3) {
|
||||||
|
if (view == null) {
|
||||||
|
view = new DrawerActionCell(mContext);
|
||||||
|
}
|
||||||
|
DrawerActionCell actionCell = (DrawerActionCell) view;
|
||||||
|
if (i == 2) {
|
||||||
|
actionCell.setTextAndIcon(LocaleController.getString("NewGroup", R.string.NewGroup), R.drawable.menu_newgroup);
|
||||||
|
} else if (i == 3) {
|
||||||
|
actionCell.setTextAndIcon(LocaleController.getString("NewSecretChat", R.string.NewSecretChat), R.drawable.menu_secret);
|
||||||
|
} else if (i == 4) {
|
||||||
|
actionCell.setTextAndIcon(LocaleController.getString("NewBroadcastList", R.string.NewBroadcastList), R.drawable.menu_broadcast);
|
||||||
|
} else if (i == 6) {
|
||||||
|
actionCell.setTextAndIcon(LocaleController.getString("Contacts", R.string.Contacts), R.drawable.menu_contacts);
|
||||||
|
} else if (i == 7) {
|
||||||
|
actionCell.setTextAndIcon(LocaleController.getString("InviteFriends", R.string.InviteFriends), R.drawable.menu_invite);
|
||||||
|
} else if (i == 8) {
|
||||||
|
actionCell.setTextAndIcon(LocaleController.getString("Settings", R.string.Settings), R.drawable.menu_settings);
|
||||||
|
} else if (i == 9) {
|
||||||
|
actionCell.setTextAndIcon(LocaleController.getString("TelegramFaq", R.string.TelegramFaq), R.drawable.menu_help);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemViewType(int i) {
|
||||||
|
if (i == 0) {
|
||||||
|
return 0;
|
||||||
|
} else if (i == 1) {
|
||||||
|
return 1;
|
||||||
|
} else if (i == 5) {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getViewTypeCount() {
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return !UserConfig.isClientActivated();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,191 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2010 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.telegram.ui.Animation;
|
||||||
|
|
||||||
|
import android.view.animation.Interpolator;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public abstract class Animator10 implements Cloneable {
|
||||||
|
|
||||||
|
ArrayList<AnimatorListener> mListeners = null;
|
||||||
|
ArrayList<AnimatorPauseListener> mPauseListeners = null;
|
||||||
|
boolean mPaused = false;
|
||||||
|
|
||||||
|
public abstract long getStartDelay();
|
||||||
|
|
||||||
|
public abstract void setStartDelay(long startDelay);
|
||||||
|
|
||||||
|
public abstract Animator10 setDuration(long duration);
|
||||||
|
|
||||||
|
public abstract long getDuration();
|
||||||
|
|
||||||
|
public abstract void setInterpolator(Interpolator value);
|
||||||
|
|
||||||
|
public abstract boolean isRunning();
|
||||||
|
|
||||||
|
public void start() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cancel() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void end() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public void pause() {
|
||||||
|
if (isStarted() && !mPaused) {
|
||||||
|
mPaused = true;
|
||||||
|
if (mPauseListeners != null) {
|
||||||
|
ArrayList<AnimatorPauseListener> tmpListeners = (ArrayList<AnimatorPauseListener>) mPauseListeners.clone();
|
||||||
|
int numListeners = tmpListeners.size();
|
||||||
|
for (AnimatorPauseListener tmpListener : tmpListeners) {
|
||||||
|
tmpListener.onAnimationPause(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public void resume() {
|
||||||
|
if (mPaused) {
|
||||||
|
mPaused = false;
|
||||||
|
if (mPauseListeners != null) {
|
||||||
|
ArrayList<AnimatorPauseListener> tmpListeners = (ArrayList<AnimatorPauseListener>) mPauseListeners.clone();
|
||||||
|
int numListeners = tmpListeners.size();
|
||||||
|
for (AnimatorPauseListener tmpListener : tmpListeners) {
|
||||||
|
tmpListener.onAnimationResume(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPaused() {
|
||||||
|
return mPaused;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isStarted() {
|
||||||
|
return isRunning();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Interpolator getInterpolator() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addListener(AnimatorListener listener) {
|
||||||
|
if (mListeners == null) {
|
||||||
|
mListeners = new ArrayList<AnimatorListener>();
|
||||||
|
}
|
||||||
|
mListeners.add(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeListener(AnimatorListener listener) {
|
||||||
|
if (mListeners == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mListeners.remove(listener);
|
||||||
|
if (mListeners.size() == 0) {
|
||||||
|
mListeners = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArrayList<AnimatorListener> getListeners() {
|
||||||
|
return mListeners;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addPauseListener(AnimatorPauseListener listener) {
|
||||||
|
if (mPauseListeners == null) {
|
||||||
|
mPauseListeners = new ArrayList<AnimatorPauseListener>();
|
||||||
|
}
|
||||||
|
mPauseListeners.add(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removePauseListener(AnimatorPauseListener listener) {
|
||||||
|
if (mPauseListeners == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mPauseListeners.remove(listener);
|
||||||
|
if (mPauseListeners.size() == 0) {
|
||||||
|
mPauseListeners = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeAllListeners() {
|
||||||
|
if (mListeners != null) {
|
||||||
|
mListeners.clear();
|
||||||
|
mListeners = null;
|
||||||
|
}
|
||||||
|
if (mPauseListeners != null) {
|
||||||
|
mPauseListeners.clear();
|
||||||
|
mPauseListeners = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Animator10 clone() {
|
||||||
|
try {
|
||||||
|
final Animator10 anim = (Animator10) super.clone();
|
||||||
|
if (mListeners != null) {
|
||||||
|
ArrayList<AnimatorListener> oldListeners = mListeners;
|
||||||
|
anim.mListeners = new ArrayList<AnimatorListener>();
|
||||||
|
int numListeners = oldListeners.size();
|
||||||
|
for (AnimatorListener oldListener : oldListeners) {
|
||||||
|
anim.mListeners.add(oldListener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mPauseListeners != null) {
|
||||||
|
ArrayList<AnimatorPauseListener> oldListeners = mPauseListeners;
|
||||||
|
anim.mPauseListeners = new ArrayList<AnimatorPauseListener>();
|
||||||
|
int numListeners = oldListeners.size();
|
||||||
|
for (AnimatorPauseListener oldListener : oldListeners) {
|
||||||
|
anim.mPauseListeners.add(oldListener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return anim;
|
||||||
|
} catch (CloneNotSupportedException e) {
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setupStartValues() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setupEndValues() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTarget(Object target) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static interface AnimatorListener {
|
||||||
|
void onAnimationStart(Animator10 animation);
|
||||||
|
void onAnimationEnd(Animator10 animation);
|
||||||
|
void onAnimationCancel(Animator10 animation);
|
||||||
|
void onAnimationRepeat(Animator10 animation);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static interface AnimatorPauseListener {
|
||||||
|
void onAnimationPause(Animator10 animation);
|
||||||
|
void onAnimationResume(Animator10 animation);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2010 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.telegram.ui.Animation;
|
||||||
|
|
||||||
|
public abstract class AnimatorListenerAdapter10 implements Animator10.AnimatorListener, Animator10.AnimatorPauseListener {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAnimationCancel(Animator10 animation) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAnimationEnd(Animator10 animation) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAnimationRepeat(Animator10 animation) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAnimationStart(Animator10 animation) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAnimationPause(Animator10 animation) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAnimationResume(Animator10 animation) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,705 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2010 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.telegram.ui.Animation;
|
||||||
|
|
||||||
|
import android.view.animation.Interpolator;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public final class AnimatorSet10 extends Animator10 {
|
||||||
|
|
||||||
|
private ArrayList<Animator10> mPlayingSet = new ArrayList<Animator10>();
|
||||||
|
private HashMap<Animator10, Node> mNodeMap = new HashMap<Animator10, Node>();
|
||||||
|
private ArrayList<Node> mNodes = new ArrayList<Node>();
|
||||||
|
private ArrayList<Node> mSortedNodes = new ArrayList<Node>();
|
||||||
|
private boolean mNeedsSort = true;
|
||||||
|
private AnimatorSetListener mSetListener = null;
|
||||||
|
boolean mTerminated = false;
|
||||||
|
private boolean mStarted = false;
|
||||||
|
private long mStartDelay = 0;
|
||||||
|
private ValueAnimator mDelayAnim = null;
|
||||||
|
private long mDuration = -1;
|
||||||
|
private Interpolator mInterpolator = null;
|
||||||
|
|
||||||
|
public void playTogether(Animator10... items) {
|
||||||
|
if (items != null) {
|
||||||
|
mNeedsSort = true;
|
||||||
|
Builder builder = play(items[0]);
|
||||||
|
for (int i = 1; i < items.length; ++i) {
|
||||||
|
builder.with(items[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void playTogether(Collection<Animator10> items) {
|
||||||
|
if (items != null && items.size() > 0) {
|
||||||
|
mNeedsSort = true;
|
||||||
|
Builder builder = null;
|
||||||
|
for (Animator10 anim : items) {
|
||||||
|
if (builder == null) {
|
||||||
|
builder = play(anim);
|
||||||
|
} else {
|
||||||
|
builder.with(anim);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void playSequentially(Animator10... items) {
|
||||||
|
if (items != null) {
|
||||||
|
mNeedsSort = true;
|
||||||
|
if (items.length == 1) {
|
||||||
|
play(items[0]);
|
||||||
|
} else {
|
||||||
|
for (int i = 0; i < items.length - 1; ++i) {
|
||||||
|
play(items[i]).before(items[i+1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void playSequentially(List<Animator10> items) {
|
||||||
|
if (items != null && items.size() > 0) {
|
||||||
|
mNeedsSort = true;
|
||||||
|
if (items.size() == 1) {
|
||||||
|
play(items.get(0));
|
||||||
|
} else {
|
||||||
|
for (int i = 0; i < items.size() - 1; ++i) {
|
||||||
|
play(items.get(i)).before(items.get(i+1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArrayList<Animator10> getChildAnimations() {
|
||||||
|
ArrayList<Animator10> childList = new ArrayList<Animator10>();
|
||||||
|
for (Node node : mNodes) {
|
||||||
|
childList.add(node.animation);
|
||||||
|
}
|
||||||
|
return childList;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setTarget(Object target) {
|
||||||
|
for (Node node : mNodes) {
|
||||||
|
Animator10 animation = node.animation;
|
||||||
|
if (animation instanceof AnimatorSet10) {
|
||||||
|
animation.setTarget(target);
|
||||||
|
} else if (animation instanceof ObjectAnimator10) {
|
||||||
|
animation.setTarget(target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setInterpolator(Interpolator interpolator) {
|
||||||
|
mInterpolator = interpolator;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Interpolator getInterpolator() {
|
||||||
|
return mInterpolator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder play(Animator10 anim) {
|
||||||
|
if (anim != null) {
|
||||||
|
mNeedsSort = true;
|
||||||
|
return new Builder(anim);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Override
|
||||||
|
public void cancel() {
|
||||||
|
mTerminated = true;
|
||||||
|
if (isStarted()) {
|
||||||
|
ArrayList<AnimatorListener> tmpListeners = null;
|
||||||
|
if (mListeners != null) {
|
||||||
|
tmpListeners = (ArrayList<AnimatorListener>) mListeners.clone();
|
||||||
|
for (AnimatorListener listener : tmpListeners) {
|
||||||
|
listener.onAnimationCancel(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mDelayAnim != null && mDelayAnim.isRunning()) {
|
||||||
|
mDelayAnim.cancel();
|
||||||
|
} else if (mSortedNodes.size() > 0) {
|
||||||
|
for (Node node : mSortedNodes) {
|
||||||
|
node.animation.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (tmpListeners != null) {
|
||||||
|
for (AnimatorListener listener : tmpListeners) {
|
||||||
|
listener.onAnimationEnd(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mStarted = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Override
|
||||||
|
public void end() {
|
||||||
|
mTerminated = true;
|
||||||
|
if (isStarted()) {
|
||||||
|
if (mSortedNodes.size() != mNodes.size()) {
|
||||||
|
// hasn't been started yet - sort the nodes now, then end them
|
||||||
|
sortNodes();
|
||||||
|
for (Node node : mSortedNodes) {
|
||||||
|
if (mSetListener == null) {
|
||||||
|
mSetListener = new AnimatorSetListener(this);
|
||||||
|
}
|
||||||
|
node.animation.addListener(mSetListener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mDelayAnim != null) {
|
||||||
|
mDelayAnim.cancel();
|
||||||
|
}
|
||||||
|
if (mSortedNodes.size() > 0) {
|
||||||
|
for (Node node : mSortedNodes) {
|
||||||
|
node.animation.end();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mListeners != null) {
|
||||||
|
ArrayList<AnimatorListener> tmpListeners = (ArrayList<AnimatorListener>) mListeners.clone();
|
||||||
|
for (AnimatorListener listener : tmpListeners) {
|
||||||
|
listener.onAnimationEnd(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mStarted = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isRunning() {
|
||||||
|
for (Node node : mNodes) {
|
||||||
|
if (node.animation.isRunning()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isStarted() {
|
||||||
|
return mStarted;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getStartDelay() {
|
||||||
|
return mStartDelay;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setStartDelay(long startDelay) {
|
||||||
|
mStartDelay = startDelay;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getDuration() {
|
||||||
|
return mDuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AnimatorSet10 setDuration(long duration) {
|
||||||
|
if (duration < 0) {
|
||||||
|
throw new IllegalArgumentException("duration must be a value of zero or greater");
|
||||||
|
}
|
||||||
|
mDuration = duration;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setupStartValues() {
|
||||||
|
for (Node node : mNodes) {
|
||||||
|
node.animation.setupStartValues();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setupEndValues() {
|
||||||
|
for (Node node : mNodes) {
|
||||||
|
node.animation.setupEndValues();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void pause() {
|
||||||
|
boolean previouslyPaused = mPaused;
|
||||||
|
super.pause();
|
||||||
|
if (!previouslyPaused && mPaused) {
|
||||||
|
if (mDelayAnim != null) {
|
||||||
|
mDelayAnim.pause();
|
||||||
|
} else {
|
||||||
|
for (Node node : mNodes) {
|
||||||
|
node.animation.pause();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void resume() {
|
||||||
|
boolean previouslyPaused = mPaused;
|
||||||
|
super.resume();
|
||||||
|
if (previouslyPaused && !mPaused) {
|
||||||
|
if (mDelayAnim != null) {
|
||||||
|
mDelayAnim.resume();
|
||||||
|
} else {
|
||||||
|
for (Node node : mNodes) {
|
||||||
|
node.animation.resume();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Override
|
||||||
|
public void start() {
|
||||||
|
mTerminated = false;
|
||||||
|
mStarted = true;
|
||||||
|
mPaused = false;
|
||||||
|
|
||||||
|
if (mDuration >= 0) {
|
||||||
|
for (Node node : mNodes) {
|
||||||
|
node.animation.setDuration(mDuration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mInterpolator != null) {
|
||||||
|
for (Node node : mNodes) {
|
||||||
|
node.animation.setInterpolator(mInterpolator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sortNodes();
|
||||||
|
|
||||||
|
int numSortedNodes = mSortedNodes.size();
|
||||||
|
for (Node node : mSortedNodes) {
|
||||||
|
ArrayList<AnimatorListener> oldListeners = node.animation.getListeners();
|
||||||
|
if (oldListeners != null && oldListeners.size() > 0) {
|
||||||
|
final ArrayList<AnimatorListener> clonedListeners = new
|
||||||
|
ArrayList<AnimatorListener>(oldListeners);
|
||||||
|
|
||||||
|
for (AnimatorListener listener : clonedListeners) {
|
||||||
|
if (listener instanceof DependencyListener ||
|
||||||
|
listener instanceof AnimatorSetListener) {
|
||||||
|
node.animation.removeListener(listener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final ArrayList<Node> nodesToStart = new ArrayList<Node>();
|
||||||
|
for (Node node : mSortedNodes) {
|
||||||
|
if (mSetListener == null) {
|
||||||
|
mSetListener = new AnimatorSetListener(this);
|
||||||
|
}
|
||||||
|
if (node.dependencies == null || node.dependencies.size() == 0) {
|
||||||
|
nodesToStart.add(node);
|
||||||
|
} else {
|
||||||
|
int numDependencies = node.dependencies.size();
|
||||||
|
for (int j = 0; j < numDependencies; ++j) {
|
||||||
|
Dependency dependency = node.dependencies.get(j);
|
||||||
|
dependency.node.animation.addListener(
|
||||||
|
new DependencyListener(this, node, dependency.rule));
|
||||||
|
}
|
||||||
|
node.tmpDependencies = (ArrayList<Dependency>) node.dependencies.clone();
|
||||||
|
}
|
||||||
|
node.animation.addListener(mSetListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mStartDelay <= 0) {
|
||||||
|
for (Node node : nodesToStart) {
|
||||||
|
node.animation.start();
|
||||||
|
mPlayingSet.add(node.animation);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mDelayAnim = ValueAnimator.ofFloat(0f, 1f);
|
||||||
|
mDelayAnim.setDuration(mStartDelay);
|
||||||
|
mDelayAnim.addListener(new AnimatorListenerAdapter10() {
|
||||||
|
boolean canceled = false;
|
||||||
|
public void onAnimationCancel(Animator10 anim) {
|
||||||
|
canceled = true;
|
||||||
|
}
|
||||||
|
public void onAnimationEnd(Animator10 anim) {
|
||||||
|
if (!canceled) {
|
||||||
|
int numNodes = nodesToStart.size();
|
||||||
|
for (Node node : nodesToStart) {
|
||||||
|
node.animation.start();
|
||||||
|
mPlayingSet.add(node.animation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mDelayAnim = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
mDelayAnim.start();
|
||||||
|
}
|
||||||
|
if (mListeners != null) {
|
||||||
|
ArrayList<AnimatorListener> tmpListeners =
|
||||||
|
(ArrayList<AnimatorListener>) mListeners.clone();
|
||||||
|
int numListeners = tmpListeners.size();
|
||||||
|
for (AnimatorListener tmpListener : tmpListeners) {
|
||||||
|
tmpListener.onAnimationStart(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mNodes.size() == 0 && mStartDelay == 0) {
|
||||||
|
mStarted = false;
|
||||||
|
if (mListeners != null) {
|
||||||
|
ArrayList<AnimatorListener> tmpListeners =
|
||||||
|
(ArrayList<AnimatorListener>) mListeners.clone();
|
||||||
|
int numListeners = tmpListeners.size();
|
||||||
|
for (AnimatorListener tmpListener : tmpListeners) {
|
||||||
|
tmpListener.onAnimationEnd(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AnimatorSet10 clone() {
|
||||||
|
final AnimatorSet10 anim = (AnimatorSet10) super.clone();
|
||||||
|
|
||||||
|
anim.mNeedsSort = true;
|
||||||
|
anim.mTerminated = false;
|
||||||
|
anim.mStarted = false;
|
||||||
|
anim.mPlayingSet = new ArrayList<Animator10>();
|
||||||
|
anim.mNodeMap = new HashMap<Animator10, Node>();
|
||||||
|
anim.mNodes = new ArrayList<Node>();
|
||||||
|
anim.mSortedNodes = new ArrayList<Node>();
|
||||||
|
|
||||||
|
HashMap<Node, Node> nodeCloneMap = new HashMap<Node, Node>();
|
||||||
|
for (Node node : mNodes) {
|
||||||
|
Node nodeClone = node.clone();
|
||||||
|
nodeCloneMap.put(node, nodeClone);
|
||||||
|
anim.mNodes.add(nodeClone);
|
||||||
|
anim.mNodeMap.put(nodeClone.animation, nodeClone);
|
||||||
|
nodeClone.dependencies = null;
|
||||||
|
nodeClone.tmpDependencies = null;
|
||||||
|
nodeClone.nodeDependents = null;
|
||||||
|
nodeClone.nodeDependencies = null;
|
||||||
|
ArrayList<AnimatorListener> cloneListeners = nodeClone.animation.getListeners();
|
||||||
|
if (cloneListeners != null) {
|
||||||
|
ArrayList<AnimatorListener> listenersToRemove = null;
|
||||||
|
for (AnimatorListener listener : cloneListeners) {
|
||||||
|
if (listener instanceof AnimatorSetListener) {
|
||||||
|
if (listenersToRemove == null) {
|
||||||
|
listenersToRemove = new ArrayList<AnimatorListener>();
|
||||||
|
}
|
||||||
|
listenersToRemove.add(listener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (listenersToRemove != null) {
|
||||||
|
for (AnimatorListener listener : listenersToRemove) {
|
||||||
|
cloneListeners.remove(listener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (Node node : mNodes) {
|
||||||
|
Node nodeClone = nodeCloneMap.get(node);
|
||||||
|
if (node.dependencies != null) {
|
||||||
|
for (Dependency dependency : node.dependencies) {
|
||||||
|
Node clonedDependencyNode = nodeCloneMap.get(dependency.node);
|
||||||
|
Dependency cloneDependency = new Dependency(clonedDependencyNode, dependency.rule);
|
||||||
|
nodeClone.addDependency(cloneDependency);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return anim;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class DependencyListener implements AnimatorListener {
|
||||||
|
|
||||||
|
private AnimatorSet10 mAnimatorSet;
|
||||||
|
private Node mNode;
|
||||||
|
private int mRule;
|
||||||
|
|
||||||
|
public DependencyListener(AnimatorSet10 animatorSet, Node node, int rule) {
|
||||||
|
this.mAnimatorSet = animatorSet;
|
||||||
|
this.mNode = node;
|
||||||
|
this.mRule = rule;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onAnimationCancel(Animator10 animation) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onAnimationEnd(Animator10 animation) {
|
||||||
|
if (mRule == Dependency.AFTER) {
|
||||||
|
startIfReady(animation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onAnimationRepeat(Animator10 animation) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onAnimationStart(Animator10 animation) {
|
||||||
|
if (mRule == Dependency.WITH) {
|
||||||
|
startIfReady(animation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startIfReady(Animator10 dependencyAnimation) {
|
||||||
|
if (mAnimatorSet.mTerminated) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Dependency dependencyToRemove = null;
|
||||||
|
int numDependencies = mNode.tmpDependencies.size();
|
||||||
|
for (int i = 0; i < numDependencies; ++i) {
|
||||||
|
Dependency dependency = mNode.tmpDependencies.get(i);
|
||||||
|
if (dependency.rule == mRule && dependency.node.animation == dependencyAnimation) {
|
||||||
|
dependencyToRemove = dependency;
|
||||||
|
dependencyAnimation.removeListener(this);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mNode.tmpDependencies.remove(dependencyToRemove);
|
||||||
|
if (mNode.tmpDependencies.size() == 0) {
|
||||||
|
mNode.animation.start();
|
||||||
|
mAnimatorSet.mPlayingSet.add(mNode.animation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class AnimatorSetListener implements AnimatorListener {
|
||||||
|
|
||||||
|
private AnimatorSet10 mAnimatorSet;
|
||||||
|
|
||||||
|
AnimatorSetListener(AnimatorSet10 animatorSet) {
|
||||||
|
mAnimatorSet = animatorSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onAnimationCancel(Animator10 animation) {
|
||||||
|
if (!mTerminated) {
|
||||||
|
if (mPlayingSet.size() == 0) {
|
||||||
|
if (mListeners != null) {
|
||||||
|
int numListeners = mListeners.size();
|
||||||
|
for (AnimatorListener mListener : mListeners) {
|
||||||
|
mListener.onAnimationCancel(mAnimatorSet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public void onAnimationEnd(Animator10 animation) {
|
||||||
|
animation.removeListener(this);
|
||||||
|
mPlayingSet.remove(animation);
|
||||||
|
Node animNode = mAnimatorSet.mNodeMap.get(animation);
|
||||||
|
animNode.done = true;
|
||||||
|
if (!mTerminated) {
|
||||||
|
ArrayList<Node> sortedNodes = mAnimatorSet.mSortedNodes;
|
||||||
|
boolean allDone = true;
|
||||||
|
int numSortedNodes = sortedNodes.size();
|
||||||
|
for (Node sortedNode : sortedNodes) {
|
||||||
|
if (!sortedNode.done) {
|
||||||
|
allDone = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (allDone) {
|
||||||
|
if (mListeners != null) {
|
||||||
|
ArrayList<AnimatorListener> tmpListeners =
|
||||||
|
(ArrayList<AnimatorListener>) mListeners.clone();
|
||||||
|
int numListeners = tmpListeners.size();
|
||||||
|
for (AnimatorListener tmpListener : tmpListeners) {
|
||||||
|
tmpListener.onAnimationEnd(mAnimatorSet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mAnimatorSet.mStarted = false;
|
||||||
|
mAnimatorSet.mPaused = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onAnimationRepeat(Animator10 animation) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onAnimationStart(Animator10 animation) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sortNodes() {
|
||||||
|
if (mNeedsSort) {
|
||||||
|
mSortedNodes.clear();
|
||||||
|
ArrayList<Node> roots = new ArrayList<Node>();
|
||||||
|
int numNodes = mNodes.size();
|
||||||
|
for (Node node : mNodes) {
|
||||||
|
if (node.dependencies == null || node.dependencies.size() == 0) {
|
||||||
|
roots.add(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ArrayList<Node> tmpRoots = new ArrayList<Node>();
|
||||||
|
while (roots.size() > 0) {
|
||||||
|
int numRoots = roots.size();
|
||||||
|
for (Node root : roots) {
|
||||||
|
mSortedNodes.add(root);
|
||||||
|
if (root.nodeDependents != null) {
|
||||||
|
int numDependents = root.nodeDependents.size();
|
||||||
|
for (int j = 0; j < numDependents; ++j) {
|
||||||
|
Node node = root.nodeDependents.get(j);
|
||||||
|
node.nodeDependencies.remove(root);
|
||||||
|
if (node.nodeDependencies.size() == 0) {
|
||||||
|
tmpRoots.add(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
roots.clear();
|
||||||
|
roots.addAll(tmpRoots);
|
||||||
|
tmpRoots.clear();
|
||||||
|
}
|
||||||
|
mNeedsSort = false;
|
||||||
|
if (mSortedNodes.size() != mNodes.size()) {
|
||||||
|
throw new IllegalStateException("Circular dependencies cannot exist in AnimatorSet");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
int numNodes = mNodes.size();
|
||||||
|
for (Node node : mNodes) {
|
||||||
|
if (node.dependencies != null && node.dependencies.size() > 0) {
|
||||||
|
int numDependencies = node.dependencies.size();
|
||||||
|
for (int j = 0; j < numDependencies; ++j) {
|
||||||
|
Dependency dependency = node.dependencies.get(j);
|
||||||
|
if (node.nodeDependencies == null) {
|
||||||
|
node.nodeDependencies = new ArrayList<Node>();
|
||||||
|
}
|
||||||
|
if (!node.nodeDependencies.contains(dependency.node)) {
|
||||||
|
node.nodeDependencies.add(dependency.node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node.done = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class Dependency {
|
||||||
|
static final int WITH = 0;
|
||||||
|
static final int AFTER = 1;
|
||||||
|
public Node node;
|
||||||
|
public int rule;
|
||||||
|
|
||||||
|
public Dependency(Node node, int rule) {
|
||||||
|
this.node = node;
|
||||||
|
this.rule = rule;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class Node implements Cloneable {
|
||||||
|
public Animator10 animation;
|
||||||
|
public ArrayList<Dependency> dependencies = null;
|
||||||
|
public ArrayList<Dependency> tmpDependencies = null;
|
||||||
|
public ArrayList<Node> nodeDependencies = null;
|
||||||
|
public ArrayList<Node> nodeDependents = null;
|
||||||
|
public boolean done = false;
|
||||||
|
|
||||||
|
public Node(Animator10 animation) {
|
||||||
|
this.animation = animation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addDependency(Dependency dependency) {
|
||||||
|
if (dependencies == null) {
|
||||||
|
dependencies = new ArrayList<Dependency>();
|
||||||
|
nodeDependencies = new ArrayList<Node>();
|
||||||
|
}
|
||||||
|
dependencies.add(dependency);
|
||||||
|
if (!nodeDependencies.contains(dependency.node)) {
|
||||||
|
nodeDependencies.add(dependency.node);
|
||||||
|
}
|
||||||
|
Node dependencyNode = dependency.node;
|
||||||
|
if (dependencyNode.nodeDependents == null) {
|
||||||
|
dependencyNode.nodeDependents = new ArrayList<Node>();
|
||||||
|
}
|
||||||
|
dependencyNode.nodeDependents.add(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Node clone() {
|
||||||
|
try {
|
||||||
|
Node node = (Node) super.clone();
|
||||||
|
node.animation = animation.clone();
|
||||||
|
return node;
|
||||||
|
} catch (CloneNotSupportedException e) {
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Builder {
|
||||||
|
|
||||||
|
private Node mCurrentNode;
|
||||||
|
|
||||||
|
Builder(Animator10 anim) {
|
||||||
|
mCurrentNode = mNodeMap.get(anim);
|
||||||
|
if (mCurrentNode == null) {
|
||||||
|
mCurrentNode = new Node(anim);
|
||||||
|
mNodeMap.put(anim, mCurrentNode);
|
||||||
|
mNodes.add(mCurrentNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder with(Animator10 anim) {
|
||||||
|
Node node = mNodeMap.get(anim);
|
||||||
|
if (node == null) {
|
||||||
|
node = new Node(anim);
|
||||||
|
mNodeMap.put(anim, node);
|
||||||
|
mNodes.add(node);
|
||||||
|
}
|
||||||
|
Dependency dependency = new Dependency(mCurrentNode, Dependency.WITH);
|
||||||
|
node.addDependency(dependency);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder before(Animator10 anim) {
|
||||||
|
Node node = mNodeMap.get(anim);
|
||||||
|
if (node == null) {
|
||||||
|
node = new Node(anim);
|
||||||
|
mNodeMap.put(anim, node);
|
||||||
|
mNodes.add(node);
|
||||||
|
}
|
||||||
|
Dependency dependency = new Dependency(mCurrentNode, Dependency.AFTER);
|
||||||
|
node.addDependency(dependency);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder after(Animator10 anim) {
|
||||||
|
Node node = mNodeMap.get(anim);
|
||||||
|
if (node == null) {
|
||||||
|
node = new Node(anim);
|
||||||
|
mNodeMap.put(anim, node);
|
||||||
|
mNodes.add(node);
|
||||||
|
}
|
||||||
|
Dependency dependency = new Dependency(node, Dependency.AFTER);
|
||||||
|
mCurrentNode.addDependency(dependency);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder after(long delay) {
|
||||||
|
ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
|
||||||
|
anim.setDuration(delay);
|
||||||
|
after(anim);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2010 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.telegram.ui.Animation;
|
||||||
|
|
||||||
|
public class FloatEvaluator implements TypeEvaluator<Number> {
|
||||||
|
public Float evaluate(float fraction, Number startValue, Number endValue) {
|
||||||
|
float startFloat = startValue.floatValue();
|
||||||
|
return startFloat + fraction * (endValue.floatValue() - startFloat);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,114 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2010 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.telegram.ui.Animation;
|
||||||
|
|
||||||
|
import android.view.animation.Interpolator;
|
||||||
|
|
||||||
|
import org.telegram.ui.Animation.Keyframe.FloatKeyframe;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
class FloatKeyframeSet extends KeyframeSet {
|
||||||
|
private float firstValue;
|
||||||
|
private float lastValue;
|
||||||
|
private float deltaValue;
|
||||||
|
private boolean firstTime = true;
|
||||||
|
|
||||||
|
public FloatKeyframeSet(FloatKeyframe... keyframes) {
|
||||||
|
super(keyframes);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getValue(float fraction) {
|
||||||
|
return getFloatValue(fraction);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FloatKeyframeSet clone() {
|
||||||
|
ArrayList<Keyframe> keyframes = mKeyframes;
|
||||||
|
int numKeyframes = mKeyframes.size();
|
||||||
|
FloatKeyframe[] newKeyframes = new FloatKeyframe[numKeyframes];
|
||||||
|
for (int i = 0; i < numKeyframes; ++i) {
|
||||||
|
newKeyframes[i] = (FloatKeyframe) keyframes.get(i).clone();
|
||||||
|
}
|
||||||
|
return new FloatKeyframeSet(newKeyframes);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public float getFloatValue(float fraction) {
|
||||||
|
if (mNumKeyframes == 2) {
|
||||||
|
if (firstTime) {
|
||||||
|
firstTime = false;
|
||||||
|
firstValue = ((FloatKeyframe) mKeyframes.get(0)).getFloatValue();
|
||||||
|
lastValue = ((FloatKeyframe) mKeyframes.get(1)).getFloatValue();
|
||||||
|
deltaValue = lastValue - firstValue;
|
||||||
|
}
|
||||||
|
if (mInterpolator != null) {
|
||||||
|
fraction = mInterpolator.getInterpolation(fraction);
|
||||||
|
}
|
||||||
|
if (mEvaluator == null) {
|
||||||
|
return firstValue + fraction * deltaValue;
|
||||||
|
} else {
|
||||||
|
return ((Number)mEvaluator.evaluate(fraction, firstValue, lastValue)).floatValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (fraction <= 0f) {
|
||||||
|
final FloatKeyframe prevKeyframe = (FloatKeyframe) mKeyframes.get(0);
|
||||||
|
final FloatKeyframe nextKeyframe = (FloatKeyframe) mKeyframes.get(1);
|
||||||
|
float prevValue = prevKeyframe.getFloatValue();
|
||||||
|
float nextValue = nextKeyframe.getFloatValue();
|
||||||
|
float prevFraction = prevKeyframe.getFraction();
|
||||||
|
float nextFraction = nextKeyframe.getFraction();
|
||||||
|
final Interpolator interpolator = nextKeyframe.getInterpolator();
|
||||||
|
if (interpolator != null) {
|
||||||
|
fraction = interpolator.getInterpolation(fraction);
|
||||||
|
}
|
||||||
|
float intervalFraction = (fraction - prevFraction) / (nextFraction - prevFraction);
|
||||||
|
return mEvaluator == null ? prevValue + intervalFraction * (nextValue - prevValue) : ((Number)mEvaluator.evaluate(intervalFraction, prevValue, nextValue)).floatValue();
|
||||||
|
} else if (fraction >= 1f) {
|
||||||
|
final FloatKeyframe prevKeyframe = (FloatKeyframe) mKeyframes.get(mNumKeyframes - 2);
|
||||||
|
final FloatKeyframe nextKeyframe = (FloatKeyframe) mKeyframes.get(mNumKeyframes - 1);
|
||||||
|
float prevValue = prevKeyframe.getFloatValue();
|
||||||
|
float nextValue = nextKeyframe.getFloatValue();
|
||||||
|
float prevFraction = prevKeyframe.getFraction();
|
||||||
|
float nextFraction = nextKeyframe.getFraction();
|
||||||
|
final Interpolator interpolator = nextKeyframe.getInterpolator();
|
||||||
|
if (interpolator != null) {
|
||||||
|
fraction = interpolator.getInterpolation(fraction);
|
||||||
|
}
|
||||||
|
float intervalFraction = (fraction - prevFraction) / (nextFraction - prevFraction);
|
||||||
|
return mEvaluator == null ? prevValue + intervalFraction * (nextValue - prevValue) : ((Number)mEvaluator.evaluate(intervalFraction, prevValue, nextValue)).floatValue();
|
||||||
|
}
|
||||||
|
FloatKeyframe prevKeyframe = (FloatKeyframe) mKeyframes.get(0);
|
||||||
|
for (int i = 1; i < mNumKeyframes; ++i) {
|
||||||
|
FloatKeyframe nextKeyframe = (FloatKeyframe) mKeyframes.get(i);
|
||||||
|
if (fraction < nextKeyframe.getFraction()) {
|
||||||
|
final Interpolator interpolator = nextKeyframe.getInterpolator();
|
||||||
|
if (interpolator != null) {
|
||||||
|
fraction = interpolator.getInterpolation(fraction);
|
||||||
|
}
|
||||||
|
float intervalFraction = (fraction - prevKeyframe.getFraction()) /
|
||||||
|
(nextKeyframe.getFraction() - prevKeyframe.getFraction());
|
||||||
|
float prevValue = prevKeyframe.getFloatValue();
|
||||||
|
float nextValue = nextKeyframe.getFloatValue();
|
||||||
|
return mEvaluator == null ? prevValue + intervalFraction * (nextValue - prevValue) : ((Number)mEvaluator.evaluate(intervalFraction, prevValue, nextValue)).floatValue();
|
||||||
|
}
|
||||||
|
prevKeyframe = nextKeyframe;
|
||||||
|
}
|
||||||
|
return ((Number)mKeyframes.get(mNumKeyframes - 1).getValue()).floatValue();
|
||||||
|
}
|
||||||
|
}
|
30
TMessagesProj/src/main/java/org/telegram/ui/Animation/FloatProperty10.java
Executable file
30
TMessagesProj/src/main/java/org/telegram/ui/Animation/FloatProperty10.java
Executable file
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2011 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.telegram.ui.Animation;
|
||||||
|
|
||||||
|
public abstract class FloatProperty10<T> extends Property<T, Float> {
|
||||||
|
|
||||||
|
public FloatProperty10(String name) {
|
||||||
|
super(Float.class, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void setValue(T object, float value);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
final public void set(T object, Float value) {
|
||||||
|
setValue(object, value.floatValue());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2010 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.telegram.ui.Animation;
|
||||||
|
|
||||||
|
public class IntEvaluator implements TypeEvaluator<Integer> {
|
||||||
|
public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
|
||||||
|
int startInt = startValue;
|
||||||
|
return (int)(startInt + fraction * (endValue - startInt));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,114 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2010 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.telegram.ui.Animation;
|
||||||
|
|
||||||
|
import android.view.animation.Interpolator;
|
||||||
|
|
||||||
|
import org.telegram.ui.Animation.Keyframe.IntKeyframe;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
class IntKeyframeSet extends KeyframeSet {
|
||||||
|
private int firstValue;
|
||||||
|
private int lastValue;
|
||||||
|
private int deltaValue;
|
||||||
|
private boolean firstTime = true;
|
||||||
|
|
||||||
|
public IntKeyframeSet(IntKeyframe... keyframes) {
|
||||||
|
super(keyframes);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getValue(float fraction) {
|
||||||
|
return getIntValue(fraction);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IntKeyframeSet clone() {
|
||||||
|
ArrayList<Keyframe> keyframes = mKeyframes;
|
||||||
|
int numKeyframes = mKeyframes.size();
|
||||||
|
IntKeyframe[] newKeyframes = new IntKeyframe[numKeyframes];
|
||||||
|
for (int i = 0; i < numKeyframes; ++i) {
|
||||||
|
newKeyframes[i] = (IntKeyframe) keyframes.get(i).clone();
|
||||||
|
}
|
||||||
|
return new IntKeyframeSet(newKeyframes);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public int getIntValue(float fraction) {
|
||||||
|
if (mNumKeyframes == 2) {
|
||||||
|
if (firstTime) {
|
||||||
|
firstTime = false;
|
||||||
|
firstValue = ((IntKeyframe) mKeyframes.get(0)).getIntValue();
|
||||||
|
lastValue = ((IntKeyframe) mKeyframes.get(1)).getIntValue();
|
||||||
|
deltaValue = lastValue - firstValue;
|
||||||
|
}
|
||||||
|
if (mInterpolator != null) {
|
||||||
|
fraction = mInterpolator.getInterpolation(fraction);
|
||||||
|
}
|
||||||
|
if (mEvaluator == null) {
|
||||||
|
return firstValue + (int)(fraction * deltaValue);
|
||||||
|
} else {
|
||||||
|
return ((Number)mEvaluator.evaluate(fraction, firstValue, lastValue)).intValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (fraction <= 0f) {
|
||||||
|
final IntKeyframe prevKeyframe = (IntKeyframe) mKeyframes.get(0);
|
||||||
|
final IntKeyframe nextKeyframe = (IntKeyframe) mKeyframes.get(1);
|
||||||
|
int prevValue = prevKeyframe.getIntValue();
|
||||||
|
int nextValue = nextKeyframe.getIntValue();
|
||||||
|
float prevFraction = prevKeyframe.getFraction();
|
||||||
|
float nextFraction = nextKeyframe.getFraction();
|
||||||
|
final Interpolator interpolator = nextKeyframe.getInterpolator();
|
||||||
|
if (interpolator != null) {
|
||||||
|
fraction = interpolator.getInterpolation(fraction);
|
||||||
|
}
|
||||||
|
float intervalFraction = (fraction - prevFraction) / (nextFraction - prevFraction);
|
||||||
|
return mEvaluator == null ? prevValue + (int)(intervalFraction * (nextValue - prevValue)) : ((Number)mEvaluator.evaluate(intervalFraction, prevValue, nextValue)).intValue();
|
||||||
|
} else if (fraction >= 1f) {
|
||||||
|
final IntKeyframe prevKeyframe = (IntKeyframe) mKeyframes.get(mNumKeyframes - 2);
|
||||||
|
final IntKeyframe nextKeyframe = (IntKeyframe) mKeyframes.get(mNumKeyframes - 1);
|
||||||
|
int prevValue = prevKeyframe.getIntValue();
|
||||||
|
int nextValue = nextKeyframe.getIntValue();
|
||||||
|
float prevFraction = prevKeyframe.getFraction();
|
||||||
|
float nextFraction = nextKeyframe.getFraction();
|
||||||
|
final Interpolator interpolator = nextKeyframe.getInterpolator();
|
||||||
|
if (interpolator != null) {
|
||||||
|
fraction = interpolator.getInterpolation(fraction);
|
||||||
|
}
|
||||||
|
float intervalFraction = (fraction - prevFraction) / (nextFraction - prevFraction);
|
||||||
|
return mEvaluator == null ? prevValue + (int)(intervalFraction * (nextValue - prevValue)) : ((Number)mEvaluator.evaluate(intervalFraction, prevValue, nextValue)).intValue();
|
||||||
|
}
|
||||||
|
IntKeyframe prevKeyframe = (IntKeyframe) mKeyframes.get(0);
|
||||||
|
for (int i = 1; i < mNumKeyframes; ++i) {
|
||||||
|
IntKeyframe nextKeyframe = (IntKeyframe) mKeyframes.get(i);
|
||||||
|
if (fraction < nextKeyframe.getFraction()) {
|
||||||
|
final Interpolator interpolator = nextKeyframe.getInterpolator();
|
||||||
|
if (interpolator != null) {
|
||||||
|
fraction = interpolator.getInterpolation(fraction);
|
||||||
|
}
|
||||||
|
float intervalFraction = (fraction - prevKeyframe.getFraction()) / (nextKeyframe.getFraction() - prevKeyframe.getFraction());
|
||||||
|
int prevValue = prevKeyframe.getIntValue();
|
||||||
|
int nextValue = nextKeyframe.getIntValue();
|
||||||
|
return mEvaluator == null ? prevValue + (int)(intervalFraction * (nextValue - prevValue)) : ((Number)mEvaluator.evaluate(intervalFraction, prevValue, nextValue)).intValue();
|
||||||
|
}
|
||||||
|
prevKeyframe = nextKeyframe;
|
||||||
|
}
|
||||||
|
return ((Number)mKeyframes.get(mNumKeyframes - 1).getValue()).intValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
30
TMessagesProj/src/main/java/org/telegram/ui/Animation/IntProperty.java
Executable file
30
TMessagesProj/src/main/java/org/telegram/ui/Animation/IntProperty.java
Executable file
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2011 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.telegram.ui.Animation;
|
||||||
|
|
||||||
|
public abstract class IntProperty<T> extends Property<T, Integer> {
|
||||||
|
|
||||||
|
public IntProperty(String name) {
|
||||||
|
super(Integer.class, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void setValue(T object, int value);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
final public void set(T object, Integer value) {
|
||||||
|
setValue(object, value.intValue());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,187 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2010 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.telegram.ui.Animation;
|
||||||
|
|
||||||
|
import android.view.animation.Interpolator;
|
||||||
|
|
||||||
|
public abstract class Keyframe implements Cloneable {
|
||||||
|
|
||||||
|
float mFraction;
|
||||||
|
Class mValueType;
|
||||||
|
private Interpolator mInterpolator = null;
|
||||||
|
boolean mHasValue = false;
|
||||||
|
|
||||||
|
public static Keyframe ofInt(float fraction, int value) {
|
||||||
|
return new IntKeyframe(fraction, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Keyframe ofInt(float fraction) {
|
||||||
|
return new IntKeyframe(fraction);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Keyframe ofFloat(float fraction, float value) {
|
||||||
|
return new FloatKeyframe(fraction, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Keyframe ofFloat(float fraction) {
|
||||||
|
return new FloatKeyframe(fraction);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Keyframe ofObject(float fraction, Object value) {
|
||||||
|
return new ObjectKeyframe(fraction, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Keyframe ofObject(float fraction) {
|
||||||
|
return new ObjectKeyframe(fraction, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasValue() {
|
||||||
|
return mHasValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract Object getValue();
|
||||||
|
public abstract void setValue(Object value);
|
||||||
|
|
||||||
|
public float getFraction() {
|
||||||
|
return mFraction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFraction(float fraction) {
|
||||||
|
mFraction = fraction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Interpolator getInterpolator() {
|
||||||
|
return mInterpolator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInterpolator(Interpolator interpolator) {
|
||||||
|
mInterpolator = interpolator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Class getType() {
|
||||||
|
return mValueType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public abstract Keyframe clone();
|
||||||
|
|
||||||
|
static class ObjectKeyframe extends Keyframe {
|
||||||
|
|
||||||
|
Object mValue;
|
||||||
|
|
||||||
|
ObjectKeyframe(float fraction, Object value) {
|
||||||
|
mFraction = fraction;
|
||||||
|
mValue = value;
|
||||||
|
mHasValue = (value != null);
|
||||||
|
mValueType = mHasValue ? value.getClass() : Object.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getValue() {
|
||||||
|
return mValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(Object value) {
|
||||||
|
mValue = value;
|
||||||
|
mHasValue = (value != null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ObjectKeyframe clone() {
|
||||||
|
ObjectKeyframe kfClone = new ObjectKeyframe(getFraction(), mHasValue ? mValue : null);
|
||||||
|
kfClone.setInterpolator(getInterpolator());
|
||||||
|
return kfClone;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class IntKeyframe extends Keyframe {
|
||||||
|
|
||||||
|
int mValue;
|
||||||
|
|
||||||
|
IntKeyframe(float fraction, int value) {
|
||||||
|
mFraction = fraction;
|
||||||
|
mValue = value;
|
||||||
|
mValueType = int.class;
|
||||||
|
mHasValue = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
IntKeyframe(float fraction) {
|
||||||
|
mFraction = fraction;
|
||||||
|
mValueType = int.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getIntValue() {
|
||||||
|
return mValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getValue() {
|
||||||
|
return mValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(Object value) {
|
||||||
|
if (value != null && value.getClass() == Integer.class) {
|
||||||
|
mValue = (Integer) value;
|
||||||
|
mHasValue = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IntKeyframe clone() {
|
||||||
|
IntKeyframe kfClone = mHasValue ? new IntKeyframe(getFraction(), mValue) : new IntKeyframe(getFraction());
|
||||||
|
kfClone.setInterpolator(getInterpolator());
|
||||||
|
return kfClone;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class FloatKeyframe extends Keyframe {
|
||||||
|
|
||||||
|
float mValue;
|
||||||
|
|
||||||
|
FloatKeyframe(float fraction, float value) {
|
||||||
|
mFraction = fraction;
|
||||||
|
mValue = value;
|
||||||
|
mValueType = float.class;
|
||||||
|
mHasValue = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
FloatKeyframe(float fraction) {
|
||||||
|
mFraction = fraction;
|
||||||
|
mValueType = float.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getFloatValue() {
|
||||||
|
return mValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getValue() {
|
||||||
|
return mValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(Object value) {
|
||||||
|
if (value != null && value.getClass() == Float.class) {
|
||||||
|
mValue = (Float) value;
|
||||||
|
mHasValue = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FloatKeyframe clone() {
|
||||||
|
FloatKeyframe kfClone = mHasValue ? new FloatKeyframe(getFraction(), mValue) : new FloatKeyframe(getFraction());
|
||||||
|
kfClone.setInterpolator(getInterpolator());
|
||||||
|
return kfClone;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,200 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2010 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.telegram.ui.Animation;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.animation.Interpolator;
|
||||||
|
|
||||||
|
import org.telegram.ui.Animation.Keyframe.IntKeyframe;
|
||||||
|
import org.telegram.ui.Animation.Keyframe.FloatKeyframe;
|
||||||
|
import org.telegram.ui.Animation.Keyframe.ObjectKeyframe;
|
||||||
|
|
||||||
|
class KeyframeSet {
|
||||||
|
|
||||||
|
int mNumKeyframes;
|
||||||
|
|
||||||
|
Keyframe mFirstKeyframe;
|
||||||
|
Keyframe mLastKeyframe;
|
||||||
|
Interpolator mInterpolator;
|
||||||
|
ArrayList<Keyframe> mKeyframes;
|
||||||
|
TypeEvaluator mEvaluator;
|
||||||
|
|
||||||
|
public KeyframeSet(Keyframe... keyframes) {
|
||||||
|
mNumKeyframes = keyframes.length;
|
||||||
|
mKeyframes = new ArrayList<Keyframe>();
|
||||||
|
mKeyframes.addAll(Arrays.asList(keyframes));
|
||||||
|
mFirstKeyframe = mKeyframes.get(0);
|
||||||
|
mLastKeyframe = mKeyframes.get(mNumKeyframes - 1);
|
||||||
|
mInterpolator = mLastKeyframe.getInterpolator();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static KeyframeSet ofInt(int... values) {
|
||||||
|
int numKeyframes = values.length;
|
||||||
|
IntKeyframe keyframes[] = new IntKeyframe[Math.max(numKeyframes,2)];
|
||||||
|
if (numKeyframes == 1) {
|
||||||
|
keyframes[0] = (IntKeyframe) Keyframe.ofInt(0f);
|
||||||
|
keyframes[1] = (IntKeyframe) Keyframe.ofInt(1f, values[0]);
|
||||||
|
} else {
|
||||||
|
keyframes[0] = (IntKeyframe) Keyframe.ofInt(0f, values[0]);
|
||||||
|
for (int i = 1; i < numKeyframes; ++i) {
|
||||||
|
keyframes[i] = (IntKeyframe) Keyframe.ofInt((float) i / (numKeyframes - 1), values[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new IntKeyframeSet(keyframes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static KeyframeSet ofFloat(float... values) {
|
||||||
|
boolean badValue = false;
|
||||||
|
int numKeyframes = values.length;
|
||||||
|
FloatKeyframe keyframes[] = new FloatKeyframe[Math.max(numKeyframes,2)];
|
||||||
|
if (numKeyframes == 1) {
|
||||||
|
keyframes[0] = (FloatKeyframe) Keyframe.ofFloat(0f);
|
||||||
|
keyframes[1] = (FloatKeyframe) Keyframe.ofFloat(1f, values[0]);
|
||||||
|
if (Float.isNaN(values[0])) {
|
||||||
|
badValue = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
keyframes[0] = (FloatKeyframe) Keyframe.ofFloat(0f, values[0]);
|
||||||
|
for (int i = 1; i < numKeyframes; ++i) {
|
||||||
|
keyframes[i] = (FloatKeyframe) Keyframe.ofFloat((float) i / (numKeyframes - 1), values[i]);
|
||||||
|
if (Float.isNaN(values[i])) {
|
||||||
|
badValue = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (badValue) {
|
||||||
|
Log.w("Animator", "Bad value (NaN) in float animator");
|
||||||
|
}
|
||||||
|
return new FloatKeyframeSet(keyframes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static KeyframeSet ofKeyframe(Keyframe... keyframes) {
|
||||||
|
int numKeyframes = keyframes.length;
|
||||||
|
boolean hasFloat = false;
|
||||||
|
boolean hasInt = false;
|
||||||
|
boolean hasOther = false;
|
||||||
|
for (Keyframe keyframe : keyframes) {
|
||||||
|
if (keyframe instanceof FloatKeyframe) {
|
||||||
|
hasFloat = true;
|
||||||
|
} else if (keyframe instanceof IntKeyframe) {
|
||||||
|
hasInt = true;
|
||||||
|
} else {
|
||||||
|
hasOther = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (hasFloat && !hasInt && !hasOther) {
|
||||||
|
FloatKeyframe floatKeyframes[] = new FloatKeyframe[numKeyframes];
|
||||||
|
for (int i = 0; i < numKeyframes; ++i) {
|
||||||
|
floatKeyframes[i] = (FloatKeyframe) keyframes[i];
|
||||||
|
}
|
||||||
|
return new FloatKeyframeSet(floatKeyframes);
|
||||||
|
} else if (hasInt && !hasFloat && !hasOther) {
|
||||||
|
IntKeyframe intKeyframes[] = new IntKeyframe[numKeyframes];
|
||||||
|
for (int i = 0; i < numKeyframes; ++i) {
|
||||||
|
intKeyframes[i] = (IntKeyframe) keyframes[i];
|
||||||
|
}
|
||||||
|
return new IntKeyframeSet(intKeyframes);
|
||||||
|
} else {
|
||||||
|
return new KeyframeSet(keyframes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static KeyframeSet ofObject(Object... values) {
|
||||||
|
int numKeyframes = values.length;
|
||||||
|
ObjectKeyframe keyframes[] = new ObjectKeyframe[Math.max(numKeyframes,2)];
|
||||||
|
if (numKeyframes == 1) {
|
||||||
|
keyframes[0] = (ObjectKeyframe) Keyframe.ofObject(0f);
|
||||||
|
keyframes[1] = (ObjectKeyframe) Keyframe.ofObject(1f, values[0]);
|
||||||
|
} else {
|
||||||
|
keyframes[0] = (ObjectKeyframe) Keyframe.ofObject(0f, values[0]);
|
||||||
|
for (int i = 1; i < numKeyframes; ++i) {
|
||||||
|
keyframes[i] = (ObjectKeyframe) Keyframe.ofObject((float) i / (numKeyframes - 1), values[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new KeyframeSet(keyframes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEvaluator(TypeEvaluator evaluator) {
|
||||||
|
mEvaluator = evaluator;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public KeyframeSet clone() {
|
||||||
|
ArrayList<Keyframe> keyframes = mKeyframes;
|
||||||
|
int numKeyframes = mKeyframes.size();
|
||||||
|
Keyframe[] newKeyframes = new Keyframe[numKeyframes];
|
||||||
|
for (int i = 0; i < numKeyframes; ++i) {
|
||||||
|
newKeyframes[i] = keyframes.get(i).clone();
|
||||||
|
}
|
||||||
|
return new KeyframeSet(newKeyframes);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public Object getValue(float fraction) {
|
||||||
|
if (mNumKeyframes == 2) {
|
||||||
|
if (mInterpolator != null) {
|
||||||
|
fraction = mInterpolator.getInterpolation(fraction);
|
||||||
|
}
|
||||||
|
return mEvaluator.evaluate(fraction, mFirstKeyframe.getValue(), mLastKeyframe.getValue());
|
||||||
|
}
|
||||||
|
if (fraction <= 0f) {
|
||||||
|
final Keyframe nextKeyframe = mKeyframes.get(1);
|
||||||
|
final Interpolator interpolator = nextKeyframe.getInterpolator();
|
||||||
|
if (interpolator != null) {
|
||||||
|
fraction = interpolator.getInterpolation(fraction);
|
||||||
|
}
|
||||||
|
final float prevFraction = mFirstKeyframe.getFraction();
|
||||||
|
float intervalFraction = (fraction - prevFraction) / (nextKeyframe.getFraction() - prevFraction);
|
||||||
|
return mEvaluator.evaluate(intervalFraction, mFirstKeyframe.getValue(), nextKeyframe.getValue());
|
||||||
|
} else if (fraction >= 1f) {
|
||||||
|
final Keyframe prevKeyframe = mKeyframes.get(mNumKeyframes - 2);
|
||||||
|
final Interpolator interpolator = mLastKeyframe.getInterpolator();
|
||||||
|
if (interpolator != null) {
|
||||||
|
fraction = interpolator.getInterpolation(fraction);
|
||||||
|
}
|
||||||
|
final float prevFraction = prevKeyframe.getFraction();
|
||||||
|
float intervalFraction = (fraction - prevFraction) / (mLastKeyframe.getFraction() - prevFraction);
|
||||||
|
return mEvaluator.evaluate(intervalFraction, prevKeyframe.getValue(), mLastKeyframe.getValue());
|
||||||
|
}
|
||||||
|
Keyframe prevKeyframe = mFirstKeyframe;
|
||||||
|
for (int i = 1; i < mNumKeyframes; ++i) {
|
||||||
|
Keyframe nextKeyframe = mKeyframes.get(i);
|
||||||
|
if (fraction < nextKeyframe.getFraction()) {
|
||||||
|
final Interpolator interpolator = nextKeyframe.getInterpolator();
|
||||||
|
if (interpolator != null) {
|
||||||
|
fraction = interpolator.getInterpolation(fraction);
|
||||||
|
}
|
||||||
|
final float prevFraction = prevKeyframe.getFraction();
|
||||||
|
float intervalFraction = (fraction - prevFraction) / (nextKeyframe.getFraction() - prevFraction);
|
||||||
|
return mEvaluator.evaluate(intervalFraction, prevKeyframe.getValue(), nextKeyframe.getValue());
|
||||||
|
}
|
||||||
|
prevKeyframe = nextKeyframe;
|
||||||
|
}
|
||||||
|
return mLastKeyframe.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
String returnVal = " ";
|
||||||
|
for (int i = 0; i < mNumKeyframes; ++i) {
|
||||||
|
returnVal += mKeyframes.get(i).getValue() + " ";
|
||||||
|
}
|
||||||
|
return returnVal;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2011 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.telegram.ui.Animation;
|
||||||
|
|
||||||
|
public class NoSuchPropertyException extends RuntimeException {
|
||||||
|
|
||||||
|
public NoSuchPropertyException(String s) {
|
||||||
|
super(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,488 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2010 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.telegram.ui.Animation;
|
||||||
|
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
public final class ObjectAnimator10 extends ValueAnimator {
|
||||||
|
|
||||||
|
private static final HashMap<String, Property> PROXY_PROPERTIES = new HashMap<String, Property>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
Property<View, Float> ALPHA = new FloatProperty10<View>("alpha") {
|
||||||
|
@Override
|
||||||
|
public void setValue(View object, float value) {
|
||||||
|
View10.wrap(object).setAlpha(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Float get(View object) {
|
||||||
|
return View10.wrap(object).getAlpha();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Property<View, Float> PIVOT_X = new FloatProperty10<View>("pivotX") {
|
||||||
|
@Override
|
||||||
|
public void setValue(View object, float value) {
|
||||||
|
View10.wrap(object).setPivotX(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Float get(View object) {
|
||||||
|
return View10.wrap(object).getPivotX();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Property<View, Float> PIVOT_Y = new FloatProperty10<View>("pivotY") {
|
||||||
|
@Override
|
||||||
|
public void setValue(View object, float value) {
|
||||||
|
View10.wrap(object).setPivotY(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Float get(View object) {
|
||||||
|
return View10.wrap(object).getPivotY();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Property<View, Float> TRANSLATION_X = new FloatProperty10<View>("translationX") {
|
||||||
|
@Override
|
||||||
|
public void setValue(View object, float value) {
|
||||||
|
View10.wrap(object).setTranslationX(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Float get(View object) {
|
||||||
|
return View10.wrap(object).getTranslationX();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Property<View, Float> TRANSLATION_Y = new FloatProperty10<View>("translationY") {
|
||||||
|
@Override
|
||||||
|
public void setValue(View object, float value) {
|
||||||
|
View10.wrap(object).setTranslationY(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Float get(View object) {
|
||||||
|
return View10.wrap(object).getTranslationY();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Property<View, Float> ROTATION = new FloatProperty10<View>("rotation") {
|
||||||
|
@Override
|
||||||
|
public void setValue(View object, float value) {
|
||||||
|
View10.wrap(object).setRotation(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Float get(View object) {
|
||||||
|
return View10.wrap(object).getRotation();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Property<View, Float> ROTATION_X = new FloatProperty10<View>("rotationX") {
|
||||||
|
@Override
|
||||||
|
public void setValue(View object, float value) {
|
||||||
|
View10.wrap(object).setRotationX(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Float get(View object) {
|
||||||
|
return View10.wrap(object).getRotationX();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Property<View, Float> ROTATION_Y = new FloatProperty10<View>("rotationY") {
|
||||||
|
@Override
|
||||||
|
public void setValue(View object, float value) {
|
||||||
|
View10.wrap(object).setRotationY(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Float get(View object) {
|
||||||
|
return View10.wrap(object).getRotationY();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Property<View, Float> SCALE_X = new FloatProperty10<View>("scaleX") {
|
||||||
|
@Override
|
||||||
|
public void setValue(View object, float value) {
|
||||||
|
View10.wrap(object).setScaleX(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Float get(View object) {
|
||||||
|
return View10.wrap(object).getScaleX();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Property<View, Float> SCALE_Y = new FloatProperty10<View>("scaleY") {
|
||||||
|
@Override
|
||||||
|
public void setValue(View object, float value) {
|
||||||
|
View10.wrap(object).setScaleY(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Float get(View object) {
|
||||||
|
return View10.wrap(object).getScaleY();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Property<View, Integer> SCROLL_X = new IntProperty<View>("scrollX") {
|
||||||
|
@Override
|
||||||
|
public void setValue(View object, int value) {
|
||||||
|
View10.wrap(object).setScrollX(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer get(View object) {
|
||||||
|
return View10.wrap(object).getScrollX();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Property<View, Integer> SCROLL_Y = new IntProperty<View>("scrollY") {
|
||||||
|
@Override
|
||||||
|
public void setValue(View object, int value) {
|
||||||
|
View10.wrap(object).setScrollY(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer get(View object) {
|
||||||
|
return View10.wrap(object).getScrollY();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Property<View, Float> X = new FloatProperty10<View>("x") {
|
||||||
|
@Override
|
||||||
|
public void setValue(View object, float value) {
|
||||||
|
View10.wrap(object).setX(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Float get(View object) {
|
||||||
|
return View10.wrap(object).getX();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Property<View, Float> Y = new FloatProperty10<View>("y") {
|
||||||
|
@Override
|
||||||
|
public void setValue(View object, float value) {
|
||||||
|
View10.wrap(object).setY(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Float get(View object) {
|
||||||
|
return View10.wrap(object).getY();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
PROXY_PROPERTIES.put("alpha", ALPHA);
|
||||||
|
PROXY_PROPERTIES.put("pivotX", PIVOT_X);
|
||||||
|
PROXY_PROPERTIES.put("pivotY", PIVOT_Y);
|
||||||
|
PROXY_PROPERTIES.put("translationX", TRANSLATION_X);
|
||||||
|
PROXY_PROPERTIES.put("translationY", TRANSLATION_Y);
|
||||||
|
PROXY_PROPERTIES.put("rotation", ROTATION);
|
||||||
|
PROXY_PROPERTIES.put("rotationX", ROTATION_X);
|
||||||
|
PROXY_PROPERTIES.put("rotationY", ROTATION_Y);
|
||||||
|
PROXY_PROPERTIES.put("scaleX", SCALE_X);
|
||||||
|
PROXY_PROPERTIES.put("scaleY", SCALE_Y);
|
||||||
|
PROXY_PROPERTIES.put("scrollX", SCROLL_X);
|
||||||
|
PROXY_PROPERTIES.put("scrollY", SCROLL_Y);
|
||||||
|
PROXY_PROPERTIES.put("x", X);
|
||||||
|
PROXY_PROPERTIES.put("y", Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object mTarget;
|
||||||
|
private String mPropertyName;
|
||||||
|
private Property mProperty;
|
||||||
|
private boolean mAutoCancel = false;
|
||||||
|
|
||||||
|
public void setPropertyName(String propertyName) {
|
||||||
|
if (mValues != null) {
|
||||||
|
PropertyValuesHolder valuesHolder = mValues[0];
|
||||||
|
String oldName = valuesHolder.getPropertyName();
|
||||||
|
valuesHolder.setPropertyName(propertyName);
|
||||||
|
mValuesMap.remove(oldName);
|
||||||
|
mValuesMap.put(propertyName, valuesHolder);
|
||||||
|
}
|
||||||
|
mPropertyName = propertyName;
|
||||||
|
mInitialized = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProperty(Property property) {
|
||||||
|
if (mValues != null) {
|
||||||
|
PropertyValuesHolder valuesHolder = mValues[0];
|
||||||
|
String oldName = valuesHolder.getPropertyName();
|
||||||
|
valuesHolder.setProperty(property);
|
||||||
|
mValuesMap.remove(oldName);
|
||||||
|
mValuesMap.put(mPropertyName, valuesHolder);
|
||||||
|
}
|
||||||
|
if (mProperty != null) {
|
||||||
|
mPropertyName = property.getName();
|
||||||
|
}
|
||||||
|
mProperty = property;
|
||||||
|
mInitialized = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPropertyName() {
|
||||||
|
String propertyName = null;
|
||||||
|
if (mPropertyName != null) {
|
||||||
|
propertyName = mPropertyName;
|
||||||
|
} else if (mProperty != null) {
|
||||||
|
propertyName = mProperty.getName();
|
||||||
|
} else if (mValues != null && mValues.length > 0) {
|
||||||
|
for (int i = 0; i < mValues.length; ++i) {
|
||||||
|
if (i == 0) {
|
||||||
|
propertyName = "";
|
||||||
|
} else {
|
||||||
|
propertyName += ",";
|
||||||
|
}
|
||||||
|
propertyName += mValues[i].getPropertyName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return propertyName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObjectAnimator10() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private ObjectAnimator10(Object target, String propertyName) {
|
||||||
|
mTarget = target;
|
||||||
|
setPropertyName(propertyName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T> ObjectAnimator10(T target, Property<T, ?> property) {
|
||||||
|
mTarget = target;
|
||||||
|
setProperty(property);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ObjectAnimator10 ofInt(Object target, String propertyName, int... values) {
|
||||||
|
ObjectAnimator10 anim = new ObjectAnimator10(target, propertyName);
|
||||||
|
anim.setIntValues(values);
|
||||||
|
return anim;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> ObjectAnimator10 ofInt(T target, Property<T, Integer> property, int... values) {
|
||||||
|
ObjectAnimator10 anim = new ObjectAnimator10(target, property);
|
||||||
|
anim.setIntValues(values);
|
||||||
|
return anim;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ObjectAnimator10 ofFloat(Object target, String propertyName, float... values) {
|
||||||
|
ObjectAnimator10 anim = new ObjectAnimator10(target, propertyName);
|
||||||
|
anim.setFloatValues(values);
|
||||||
|
return anim;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> ObjectAnimator10 ofFloat(T target, Property<T, Float> property, float... values) {
|
||||||
|
ObjectAnimator10 anim = new ObjectAnimator10(target, property);
|
||||||
|
anim.setFloatValues(values);
|
||||||
|
return anim;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ObjectAnimator10 ofObject(Object target, String propertyName, TypeEvaluator evaluator, Object... values) {
|
||||||
|
ObjectAnimator10 anim = new ObjectAnimator10(target, propertyName);
|
||||||
|
anim.setObjectValues(values);
|
||||||
|
anim.setEvaluator(evaluator);
|
||||||
|
return anim;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T, V> ObjectAnimator10 ofObject(T target, Property<T, V> property, TypeEvaluator<V> evaluator, V... values) {
|
||||||
|
ObjectAnimator10 anim = new ObjectAnimator10(target, property);
|
||||||
|
anim.setObjectValues(values);
|
||||||
|
anim.setEvaluator(evaluator);
|
||||||
|
return anim;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ObjectAnimator10 ofPropertyValuesHolder(Object target, PropertyValuesHolder... values) {
|
||||||
|
ObjectAnimator10 anim = new ObjectAnimator10();
|
||||||
|
anim.mTarget = target;
|
||||||
|
anim.setValues(values);
|
||||||
|
return anim;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Override
|
||||||
|
public void setIntValues(int... values) {
|
||||||
|
if (mValues == null || mValues.length == 0) {
|
||||||
|
if (mProperty != null) {
|
||||||
|
setValues(PropertyValuesHolder.ofInt(mProperty, values));
|
||||||
|
} else {
|
||||||
|
setValues(PropertyValuesHolder.ofInt(mPropertyName, values));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
super.setIntValues(values);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Override
|
||||||
|
public void setFloatValues(float... values) {
|
||||||
|
if (mValues == null || mValues.length == 0) {
|
||||||
|
if (mProperty != null) {
|
||||||
|
setValues(PropertyValuesHolder.ofFloat(mProperty, values));
|
||||||
|
} else {
|
||||||
|
setValues(PropertyValuesHolder.ofFloat(mPropertyName, values));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
super.setFloatValues(values);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setObjectValues(Object... values) {
|
||||||
|
if (mValues == null || mValues.length == 0) {
|
||||||
|
if (mProperty != null) {
|
||||||
|
setValues(PropertyValuesHolder.ofObject(mProperty, null, values));
|
||||||
|
} else {
|
||||||
|
setValues(PropertyValuesHolder.ofObject(mPropertyName, null, values));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
super.setObjectValues(values);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAutoCancel(boolean cancel) {
|
||||||
|
mAutoCancel = cancel;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasSameTargetAndProperties(Animator10 anim) {
|
||||||
|
if (anim instanceof ObjectAnimator10) {
|
||||||
|
PropertyValuesHolder[] theirValues = ((ObjectAnimator10) anim).getValues();
|
||||||
|
if (((ObjectAnimator10) anim).getTarget() == mTarget &&
|
||||||
|
mValues.length == theirValues.length) {
|
||||||
|
for (int i = 0; i < mValues.length; ++i) {
|
||||||
|
PropertyValuesHolder pvhMine = mValues[i];
|
||||||
|
PropertyValuesHolder pvhTheirs = theirValues[i];
|
||||||
|
if (pvhMine.getPropertyName() == null ||
|
||||||
|
!pvhMine.getPropertyName().equals(pvhTheirs.getPropertyName())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void start() {
|
||||||
|
AnimationHandler handler = sAnimationHandler.get();
|
||||||
|
if (handler != null) {
|
||||||
|
int numAnims = handler.mAnimations.size();
|
||||||
|
for (int i = numAnims - 1; i >= 0; i--) {
|
||||||
|
if (handler.mAnimations.get(i) instanceof ObjectAnimator10) {
|
||||||
|
ObjectAnimator10 anim = (ObjectAnimator10) handler.mAnimations.get(i);
|
||||||
|
if (anim.mAutoCancel && hasSameTargetAndProperties(anim)) {
|
||||||
|
anim.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
numAnims = handler.mPendingAnimations.size();
|
||||||
|
for (int i = numAnims - 1; i >= 0; i--) {
|
||||||
|
if (handler.mPendingAnimations.get(i) instanceof ObjectAnimator10) {
|
||||||
|
ObjectAnimator10 anim = (ObjectAnimator10) handler.mPendingAnimations.get(i);
|
||||||
|
if (anim.mAutoCancel && hasSameTargetAndProperties(anim)) {
|
||||||
|
anim.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
numAnims = handler.mDelayedAnims.size();
|
||||||
|
for (int i = numAnims - 1; i >= 0; i--) {
|
||||||
|
if (handler.mDelayedAnims.get(i) instanceof ObjectAnimator10) {
|
||||||
|
ObjectAnimator10 anim = (ObjectAnimator10) handler.mDelayedAnims.get(i);
|
||||||
|
if (anim.mAutoCancel && hasSameTargetAndProperties(anim)) {
|
||||||
|
anim.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
super.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void initAnimation() {
|
||||||
|
if (!mInitialized) {
|
||||||
|
if ((mProperty == null) && (mTarget instanceof View) && PROXY_PROPERTIES.containsKey(mPropertyName)) {
|
||||||
|
setProperty(PROXY_PROPERTIES.get(mPropertyName));
|
||||||
|
}
|
||||||
|
int numValues = mValues.length;
|
||||||
|
for (PropertyValuesHolder mValue : mValues) {
|
||||||
|
mValue.setupSetterAndGetter(mTarget);
|
||||||
|
}
|
||||||
|
super.initAnimation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ObjectAnimator10 setDuration(long duration) {
|
||||||
|
super.setDuration(duration);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getTarget() {
|
||||||
|
return mTarget;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setTarget(Object target) {
|
||||||
|
if (mTarget != target) {
|
||||||
|
final Object oldTarget = mTarget;
|
||||||
|
mTarget = target;
|
||||||
|
if (oldTarget != null && target != null && oldTarget.getClass() == target.getClass()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mInitialized = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setupStartValues() {
|
||||||
|
initAnimation();
|
||||||
|
int numValues = mValues.length;
|
||||||
|
for (PropertyValuesHolder mValue : mValues) {
|
||||||
|
mValue.setupStartValue(mTarget);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setupEndValues() {
|
||||||
|
initAnimation();
|
||||||
|
int numValues = mValues.length;
|
||||||
|
for (PropertyValuesHolder mValue : mValues) {
|
||||||
|
mValue.setupEndValue(mTarget);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void animateValue(float fraction) {
|
||||||
|
super.animateValue(fraction);
|
||||||
|
int numValues = mValues.length;
|
||||||
|
for (PropertyValuesHolder mValue : mValues) {
|
||||||
|
mValue.setAnimatedValue(mTarget);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ObjectAnimator10 clone() {
|
||||||
|
return (ObjectAnimator10) super.clone();
|
||||||
|
}
|
||||||
|
}
|
49
TMessagesProj/src/main/java/org/telegram/ui/Animation/Property.java
Executable file
49
TMessagesProj/src/main/java/org/telegram/ui/Animation/Property.java
Executable file
@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2011 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.telegram.ui.Animation;
|
||||||
|
|
||||||
|
public abstract class Property<T, V> {
|
||||||
|
|
||||||
|
private final String mName;
|
||||||
|
private final Class<V> mType;
|
||||||
|
|
||||||
|
public static <T, V> Property<T, V> of(Class<T> hostType, Class<V> valueType, String name) {
|
||||||
|
return new ReflectiveProperty<T, V>(hostType, valueType, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Property(Class<V> type, String name) {
|
||||||
|
mName = name;
|
||||||
|
mType = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isReadOnly() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void set(T object, V value) {
|
||||||
|
throw new UnsupportedOperationException("Property " + getName() +" is read-only");
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract V get(T object);
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return mName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Class<V> getType() {
|
||||||
|
return mType;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,556 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2010 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.telegram.ui.Animation;
|
||||||
|
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||||
|
|
||||||
|
public class PropertyValuesHolder implements Cloneable {
|
||||||
|
|
||||||
|
String mPropertyName;
|
||||||
|
protected Property mProperty;
|
||||||
|
Method mSetter = null;
|
||||||
|
private Method mGetter = null;
|
||||||
|
Class mValueType;
|
||||||
|
KeyframeSet mKeyframeSet = null;
|
||||||
|
|
||||||
|
private static final TypeEvaluator sIntEvaluator = new IntEvaluator();
|
||||||
|
private static final TypeEvaluator sFloatEvaluator = new FloatEvaluator();
|
||||||
|
|
||||||
|
private static Class[] FLOAT_VARIANTS = {float.class, Float.class, double.class, int.class, Double.class, Integer.class};
|
||||||
|
private static Class[] INTEGER_VARIANTS = {int.class, Integer.class, float.class, double.class, Float.class, Double.class};
|
||||||
|
private static Class[] DOUBLE_VARIANTS = {double.class, Double.class, float.class, int.class, Float.class, Integer.class};
|
||||||
|
|
||||||
|
private static final HashMap<Class, HashMap<String, Method>> sSetterPropertyMap = new HashMap<Class, HashMap<String, Method>>();
|
||||||
|
private static final HashMap<Class, HashMap<String, Method>> sGetterPropertyMap = new HashMap<Class, HashMap<String, Method>>();
|
||||||
|
|
||||||
|
final ReentrantReadWriteLock mPropertyMapLock = new ReentrantReadWriteLock();
|
||||||
|
final Object[] mTmpValueArray = new Object[1];
|
||||||
|
|
||||||
|
private TypeEvaluator mEvaluator;
|
||||||
|
|
||||||
|
private Object mAnimatedValue;
|
||||||
|
|
||||||
|
private PropertyValuesHolder(String propertyName) {
|
||||||
|
mPropertyName = propertyName;
|
||||||
|
}
|
||||||
|
|
||||||
|
private PropertyValuesHolder(Property property) {
|
||||||
|
mProperty = property;
|
||||||
|
if (property != null) {
|
||||||
|
mPropertyName = property.getName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PropertyValuesHolder ofInt(String propertyName, int... values) {
|
||||||
|
return new IntPropertyValuesHolder(propertyName, values);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PropertyValuesHolder ofInt(Property<?, Integer> property, int... values) {
|
||||||
|
return new IntPropertyValuesHolder(property, values);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PropertyValuesHolder ofFloat(String propertyName, float... values) {
|
||||||
|
return new FloatPropertyValuesHolder(propertyName, values);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PropertyValuesHolder ofFloat(Property<?, Float> property, float... values) {
|
||||||
|
return new FloatPropertyValuesHolder(property, values);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PropertyValuesHolder ofObject(String propertyName, TypeEvaluator evaluator,
|
||||||
|
Object... values) {
|
||||||
|
PropertyValuesHolder pvh = new PropertyValuesHolder(propertyName);
|
||||||
|
pvh.setObjectValues(values);
|
||||||
|
pvh.setEvaluator(evaluator);
|
||||||
|
return pvh;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <V> PropertyValuesHolder ofObject(Property property,
|
||||||
|
TypeEvaluator<V> evaluator, V... values) {
|
||||||
|
PropertyValuesHolder pvh = new PropertyValuesHolder(property);
|
||||||
|
pvh.setObjectValues(values);
|
||||||
|
pvh.setEvaluator(evaluator);
|
||||||
|
return pvh;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PropertyValuesHolder ofKeyframe(String propertyName, Keyframe... values) {
|
||||||
|
KeyframeSet keyframeSet = KeyframeSet.ofKeyframe(values);
|
||||||
|
if (keyframeSet instanceof IntKeyframeSet) {
|
||||||
|
return new IntPropertyValuesHolder(propertyName, (IntKeyframeSet) keyframeSet);
|
||||||
|
} else if (keyframeSet instanceof FloatKeyframeSet) {
|
||||||
|
return new FloatPropertyValuesHolder(propertyName, (FloatKeyframeSet) keyframeSet);
|
||||||
|
} else {
|
||||||
|
PropertyValuesHolder pvh = new PropertyValuesHolder(propertyName);
|
||||||
|
pvh.mKeyframeSet = keyframeSet;
|
||||||
|
pvh.mValueType = values[0].getType();
|
||||||
|
return pvh;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PropertyValuesHolder ofKeyframe(Property property, Keyframe... values) {
|
||||||
|
KeyframeSet keyframeSet = KeyframeSet.ofKeyframe(values);
|
||||||
|
if (keyframeSet instanceof IntKeyframeSet) {
|
||||||
|
return new IntPropertyValuesHolder(property, (IntKeyframeSet) keyframeSet);
|
||||||
|
} else if (keyframeSet instanceof FloatKeyframeSet) {
|
||||||
|
return new FloatPropertyValuesHolder(property, (FloatKeyframeSet) keyframeSet);
|
||||||
|
} else {
|
||||||
|
PropertyValuesHolder pvh = new PropertyValuesHolder(property);
|
||||||
|
pvh.mKeyframeSet = keyframeSet;
|
||||||
|
pvh.mValueType = values[0].getType();
|
||||||
|
return pvh;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIntValues(int... values) {
|
||||||
|
mValueType = int.class;
|
||||||
|
mKeyframeSet = KeyframeSet.ofInt(values);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFloatValues(float... values) {
|
||||||
|
mValueType = float.class;
|
||||||
|
mKeyframeSet = KeyframeSet.ofFloat(values);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setKeyframes(Keyframe... values) {
|
||||||
|
int numKeyframes = values.length;
|
||||||
|
Keyframe keyframes[] = new Keyframe[Math.max(numKeyframes, 2)];
|
||||||
|
mValueType = values[0].getType();
|
||||||
|
System.arraycopy(values, 0, keyframes, 0, numKeyframes);
|
||||||
|
mKeyframeSet = new KeyframeSet(keyframes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setObjectValues(Object... values) {
|
||||||
|
mValueType = values[0].getClass();
|
||||||
|
mKeyframeSet = KeyframeSet.ofObject(values);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private Method getPropertyFunction(Class targetClass, String prefix, Class valueType) {
|
||||||
|
Method returnVal = null;
|
||||||
|
String methodName = getMethodName(prefix, mPropertyName);
|
||||||
|
Class args[] = null;
|
||||||
|
if (valueType == null) {
|
||||||
|
try {
|
||||||
|
returnVal = targetClass.getMethod(methodName);
|
||||||
|
} catch (NoSuchMethodException e) {
|
||||||
|
try {
|
||||||
|
returnVal = targetClass.getDeclaredMethod(methodName);
|
||||||
|
returnVal.setAccessible(true);
|
||||||
|
} catch (NoSuchMethodException e2) {
|
||||||
|
e2.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
args = new Class[1];
|
||||||
|
Class typeVariants[];
|
||||||
|
if (mValueType.equals(Float.class)) {
|
||||||
|
typeVariants = FLOAT_VARIANTS;
|
||||||
|
} else if (mValueType.equals(Integer.class)) {
|
||||||
|
typeVariants = INTEGER_VARIANTS;
|
||||||
|
} else if (mValueType.equals(Double.class)) {
|
||||||
|
typeVariants = DOUBLE_VARIANTS;
|
||||||
|
} else {
|
||||||
|
typeVariants = new Class[1];
|
||||||
|
typeVariants[0] = mValueType;
|
||||||
|
}
|
||||||
|
for (Class typeVariant : typeVariants) {
|
||||||
|
args[0] = typeVariant;
|
||||||
|
try {
|
||||||
|
returnVal = targetClass.getMethod(methodName, args);
|
||||||
|
mValueType = typeVariant;
|
||||||
|
return returnVal;
|
||||||
|
} catch (NoSuchMethodException e) {
|
||||||
|
try {
|
||||||
|
returnVal = targetClass.getDeclaredMethod(methodName, args);
|
||||||
|
returnVal.setAccessible(true);
|
||||||
|
mValueType = typeVariant;
|
||||||
|
return returnVal;
|
||||||
|
} catch (NoSuchMethodException e2) {
|
||||||
|
// Swallow the error and keep trying other variants
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Method setupSetterOrGetter(Class targetClass, HashMap<Class, HashMap<String, Method>> propertyMapMap, String prefix, Class valueType) {
|
||||||
|
Method setterOrGetter = null;
|
||||||
|
try {
|
||||||
|
mPropertyMapLock.writeLock().lock();
|
||||||
|
HashMap<String, Method> propertyMap = propertyMapMap.get(targetClass);
|
||||||
|
if (propertyMap != null) {
|
||||||
|
setterOrGetter = propertyMap.get(mPropertyName);
|
||||||
|
}
|
||||||
|
if (setterOrGetter == null) {
|
||||||
|
setterOrGetter = getPropertyFunction(targetClass, prefix, valueType);
|
||||||
|
if (propertyMap == null) {
|
||||||
|
propertyMap = new HashMap<String, Method>();
|
||||||
|
propertyMapMap.put(targetClass, propertyMap);
|
||||||
|
}
|
||||||
|
propertyMap.put(mPropertyName, setterOrGetter);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
mPropertyMapLock.writeLock().unlock();
|
||||||
|
}
|
||||||
|
return setterOrGetter;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setupSetter(Class targetClass) {
|
||||||
|
mSetter = setupSetterOrGetter(targetClass, sSetterPropertyMap, "set", mValueType);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupGetter(Class targetClass) {
|
||||||
|
mGetter = setupSetterOrGetter(targetClass, sGetterPropertyMap, "get", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
void setupSetterAndGetter(Object target) {
|
||||||
|
if (mProperty != null) {
|
||||||
|
try {
|
||||||
|
Object testValue = mProperty.get(target);
|
||||||
|
for (Keyframe kf : mKeyframeSet.mKeyframes) {
|
||||||
|
if (!kf.hasValue()) {
|
||||||
|
kf.setValue(mProperty.get(target));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
} catch (ClassCastException e) {
|
||||||
|
mProperty = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Class targetClass = target.getClass();
|
||||||
|
if (mSetter == null) {
|
||||||
|
setupSetter(targetClass);
|
||||||
|
}
|
||||||
|
for (Keyframe kf : mKeyframeSet.mKeyframes) {
|
||||||
|
if (!kf.hasValue()) {
|
||||||
|
if (mGetter == null) {
|
||||||
|
setupGetter(targetClass);
|
||||||
|
if (mGetter == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
kf.setValue(mGetter.invoke(target));
|
||||||
|
} catch (InvocationTargetException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private void setupValue(Object target, Keyframe kf) {
|
||||||
|
if (mProperty != null) {
|
||||||
|
kf.setValue(mProperty.get(target));
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if (mGetter == null) {
|
||||||
|
Class targetClass = target.getClass();
|
||||||
|
setupGetter(targetClass);
|
||||||
|
if (mGetter == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
kf.setValue(mGetter.invoke(target));
|
||||||
|
} catch (InvocationTargetException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setupStartValue(Object target) {
|
||||||
|
setupValue(target, mKeyframeSet.mKeyframes.get(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
void setupEndValue(Object target) {
|
||||||
|
setupValue(target, mKeyframeSet.mKeyframes.get(mKeyframeSet.mKeyframes.size() - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PropertyValuesHolder clone() {
|
||||||
|
try {
|
||||||
|
PropertyValuesHolder newPVH = (PropertyValuesHolder) super.clone();
|
||||||
|
newPVH.mPropertyName = mPropertyName;
|
||||||
|
newPVH.mProperty = mProperty;
|
||||||
|
newPVH.mKeyframeSet = mKeyframeSet.clone();
|
||||||
|
newPVH.mEvaluator = mEvaluator;
|
||||||
|
return newPVH;
|
||||||
|
} catch (CloneNotSupportedException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
void setAnimatedValue(Object target) {
|
||||||
|
if (mProperty != null) {
|
||||||
|
mProperty.set(target, getAnimatedValue());
|
||||||
|
}
|
||||||
|
if (mSetter != null) {
|
||||||
|
try {
|
||||||
|
mTmpValueArray[0] = getAnimatedValue();
|
||||||
|
mSetter.invoke(target, mTmpValueArray);
|
||||||
|
} catch (InvocationTargetException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void init() {
|
||||||
|
if (mEvaluator == null) {
|
||||||
|
mEvaluator = (mValueType == Integer.class) ? sIntEvaluator : (mValueType == Float.class) ? sFloatEvaluator : null;
|
||||||
|
}
|
||||||
|
if (mEvaluator != null) {
|
||||||
|
mKeyframeSet.setEvaluator(mEvaluator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEvaluator(TypeEvaluator evaluator) {
|
||||||
|
mEvaluator = evaluator;
|
||||||
|
mKeyframeSet.setEvaluator(evaluator);
|
||||||
|
}
|
||||||
|
|
||||||
|
void calculateValue(float fraction) {
|
||||||
|
mAnimatedValue = mKeyframeSet.getValue(fraction);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPropertyName(String propertyName) {
|
||||||
|
mPropertyName = propertyName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProperty(Property property) {
|
||||||
|
mProperty = property;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPropertyName() {
|
||||||
|
return mPropertyName;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object getAnimatedValue() {
|
||||||
|
return mAnimatedValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return mPropertyName + ": " + mKeyframeSet.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
static String getMethodName(String prefix, String propertyName) {
|
||||||
|
if (propertyName == null || propertyName.length() == 0) {
|
||||||
|
return prefix;
|
||||||
|
}
|
||||||
|
char firstLetter = Character.toUpperCase(propertyName.charAt(0));
|
||||||
|
String theRest = propertyName.substring(1);
|
||||||
|
return prefix + firstLetter + theRest;
|
||||||
|
}
|
||||||
|
|
||||||
|
static class IntPropertyValuesHolder extends PropertyValuesHolder {
|
||||||
|
private static final HashMap<Class, HashMap<String, Integer>> sJNISetterPropertyMap = new HashMap<Class, HashMap<String, Integer>>();
|
||||||
|
private IntProperty mIntProperty;
|
||||||
|
|
||||||
|
IntKeyframeSet mIntKeyframeSet;
|
||||||
|
int mIntAnimatedValue;
|
||||||
|
|
||||||
|
public IntPropertyValuesHolder(String propertyName, IntKeyframeSet keyframeSet) {
|
||||||
|
super(propertyName);
|
||||||
|
mValueType = int.class;
|
||||||
|
mKeyframeSet = keyframeSet;
|
||||||
|
mIntKeyframeSet = (IntKeyframeSet) mKeyframeSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IntPropertyValuesHolder(Property property, IntKeyframeSet keyframeSet) {
|
||||||
|
super(property);
|
||||||
|
mValueType = int.class;
|
||||||
|
mKeyframeSet = keyframeSet;
|
||||||
|
mIntKeyframeSet = (IntKeyframeSet) mKeyframeSet;
|
||||||
|
if (property instanceof IntProperty) {
|
||||||
|
mIntProperty = (IntProperty) mProperty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public IntPropertyValuesHolder(String propertyName, int... values) {
|
||||||
|
super(propertyName);
|
||||||
|
setIntValues(values);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IntPropertyValuesHolder(Property property, int... values) {
|
||||||
|
super(property);
|
||||||
|
setIntValues(values);
|
||||||
|
if (property instanceof IntProperty) {
|
||||||
|
mIntProperty = (IntProperty) mProperty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setIntValues(int... values) {
|
||||||
|
super.setIntValues(values);
|
||||||
|
mIntKeyframeSet = (IntKeyframeSet) mKeyframeSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void calculateValue(float fraction) {
|
||||||
|
mIntAnimatedValue = mIntKeyframeSet.getIntValue(fraction);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
Object getAnimatedValue() {
|
||||||
|
return mIntAnimatedValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IntPropertyValuesHolder clone() {
|
||||||
|
IntPropertyValuesHolder newPVH = (IntPropertyValuesHolder) super.clone();
|
||||||
|
newPVH.mIntKeyframeSet = (IntKeyframeSet) newPVH.mKeyframeSet;
|
||||||
|
return newPVH;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Override
|
||||||
|
void setAnimatedValue(Object target) {
|
||||||
|
if (mIntProperty != null) {
|
||||||
|
mIntProperty.setValue(target, mIntAnimatedValue);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (mProperty != null) {
|
||||||
|
mProperty.set(target, mIntAnimatedValue);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (mSetter != null) {
|
||||||
|
try {
|
||||||
|
mTmpValueArray[0] = mIntAnimatedValue;
|
||||||
|
mSetter.invoke(target, mTmpValueArray);
|
||||||
|
} catch (InvocationTargetException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void setupSetter(Class targetClass) {
|
||||||
|
if (mProperty != null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
super.setupSetter(targetClass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class FloatPropertyValuesHolder extends PropertyValuesHolder {
|
||||||
|
|
||||||
|
private static final HashMap<Class, HashMap<String, Integer>> sJNISetterPropertyMap = new HashMap<Class, HashMap<String, Integer>>();
|
||||||
|
private FloatProperty10 mFloatProperty;
|
||||||
|
|
||||||
|
FloatKeyframeSet mFloatKeyframeSet;
|
||||||
|
float mFloatAnimatedValue;
|
||||||
|
|
||||||
|
public FloatPropertyValuesHolder(String propertyName, FloatKeyframeSet keyframeSet) {
|
||||||
|
super(propertyName);
|
||||||
|
mValueType = float.class;
|
||||||
|
mKeyframeSet = keyframeSet;
|
||||||
|
mFloatKeyframeSet = (FloatKeyframeSet) mKeyframeSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FloatPropertyValuesHolder(Property property, FloatKeyframeSet keyframeSet) {
|
||||||
|
super(property);
|
||||||
|
mValueType = float.class;
|
||||||
|
mKeyframeSet = keyframeSet;
|
||||||
|
mFloatKeyframeSet = (FloatKeyframeSet) mKeyframeSet;
|
||||||
|
if (property instanceof FloatProperty10) {
|
||||||
|
mFloatProperty = (FloatProperty10) mProperty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public FloatPropertyValuesHolder(String propertyName, float... values) {
|
||||||
|
super(propertyName);
|
||||||
|
setFloatValues(values);
|
||||||
|
}
|
||||||
|
|
||||||
|
public FloatPropertyValuesHolder(Property property, float... values) {
|
||||||
|
super(property);
|
||||||
|
setFloatValues(values);
|
||||||
|
if (property instanceof FloatProperty10) {
|
||||||
|
mFloatProperty = (FloatProperty10) mProperty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setFloatValues(float... values) {
|
||||||
|
super.setFloatValues(values);
|
||||||
|
mFloatKeyframeSet = (FloatKeyframeSet) mKeyframeSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void calculateValue(float fraction) {
|
||||||
|
mFloatAnimatedValue = mFloatKeyframeSet.getFloatValue(fraction);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
Object getAnimatedValue() {
|
||||||
|
return mFloatAnimatedValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FloatPropertyValuesHolder clone() {
|
||||||
|
FloatPropertyValuesHolder newPVH = (FloatPropertyValuesHolder) super.clone();
|
||||||
|
newPVH.mFloatKeyframeSet = (FloatKeyframeSet) newPVH.mKeyframeSet;
|
||||||
|
return newPVH;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Override
|
||||||
|
void setAnimatedValue(Object target) {
|
||||||
|
if (mFloatProperty != null) {
|
||||||
|
mFloatProperty.setValue(target, mFloatAnimatedValue);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (mProperty != null) {
|
||||||
|
mProperty.set(target, mFloatAnimatedValue);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (mSetter != null) {
|
||||||
|
try {
|
||||||
|
mTmpValueArray[0] = mFloatAnimatedValue;
|
||||||
|
mSetter.invoke(target, mTmpValueArray);
|
||||||
|
} catch (InvocationTargetException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void setupSetter(Class targetClass) {
|
||||||
|
if (mProperty != null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
super.setupSetter(targetClass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
182
TMessagesProj/src/main/java/org/telegram/ui/Animation/ReflectiveProperty.java
Executable file
182
TMessagesProj/src/main/java/org/telegram/ui/Animation/ReflectiveProperty.java
Executable file
@ -0,0 +1,182 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2011 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.telegram.ui.Animation;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal class to automatically generate a Property for a given class/name pair, given the
|
||||||
|
* specification of {@link Property#of(java.lang.Class, java.lang.Class, java.lang.String)}
|
||||||
|
*/
|
||||||
|
class ReflectiveProperty<T, V> extends Property<T, V> {
|
||||||
|
|
||||||
|
private static final String PREFIX_GET = "get";
|
||||||
|
private static final String PREFIX_IS = "is";
|
||||||
|
private static final String PREFIX_SET = "set";
|
||||||
|
private Method mSetter;
|
||||||
|
private Method mGetter;
|
||||||
|
private Field mField;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For given property name 'name', look for getName/isName method or 'name' field.
|
||||||
|
* Also look for setName method (optional - could be readonly). Failing method getters and
|
||||||
|
* field results in throwing NoSuchPropertyException.
|
||||||
|
*
|
||||||
|
* @param propertyHolder The class on which the methods or field are found
|
||||||
|
* @param name The name of the property, where this name is capitalized and appended to
|
||||||
|
* "get" and "is to search for the appropriate methods. If the get/is methods are not found,
|
||||||
|
* the constructor will search for a field with that exact name.
|
||||||
|
*/
|
||||||
|
public ReflectiveProperty(Class<T> propertyHolder, Class<V> valueType, String name) {
|
||||||
|
// TODO: cache reflection info for each new class/name pair
|
||||||
|
super(valueType, name);
|
||||||
|
char firstLetter = Character.toUpperCase(name.charAt(0));
|
||||||
|
String theRest = name.substring(1);
|
||||||
|
String capitalizedName = firstLetter + theRest;
|
||||||
|
String getterName = PREFIX_GET + capitalizedName;
|
||||||
|
try {
|
||||||
|
mGetter = propertyHolder.getMethod(getterName, (Class<?>[]) null);
|
||||||
|
} catch (NoSuchMethodException e) {
|
||||||
|
try {
|
||||||
|
/* The native implementation uses JNI to do reflection, which allows access to private methods.
|
||||||
|
* getDeclaredMethod(..) does not find superclass methods, so it's implemented as a fallback.
|
||||||
|
*/
|
||||||
|
mGetter = propertyHolder.getDeclaredMethod(getterName, (Class<?>[]) null);
|
||||||
|
mGetter.setAccessible(true);
|
||||||
|
} catch (NoSuchMethodException e2) {
|
||||||
|
// getName() not available - try isName() instead
|
||||||
|
getterName = PREFIX_IS + capitalizedName;
|
||||||
|
try {
|
||||||
|
mGetter = propertyHolder.getMethod(getterName, (Class<?>[]) null);
|
||||||
|
} catch (NoSuchMethodException e3) {
|
||||||
|
try {
|
||||||
|
/* The native implementation uses JNI to do reflection, which allows access to private methods.
|
||||||
|
* getDeclaredMethod(..) does not find superclass methods, so it's implemented as a fallback.
|
||||||
|
*/
|
||||||
|
mGetter = propertyHolder.getDeclaredMethod(getterName, (Class<?>[]) null);
|
||||||
|
mGetter.setAccessible(true);
|
||||||
|
} catch (NoSuchMethodException e4) {
|
||||||
|
// Try public field instead
|
||||||
|
try {
|
||||||
|
mField = propertyHolder.getField(name);
|
||||||
|
Class fieldType = mField.getType();
|
||||||
|
if (!typesMatch(valueType, fieldType)) {
|
||||||
|
throw new NoSuchPropertyException("Underlying type (" + fieldType + ") " +
|
||||||
|
"does not match Property type (" + valueType + ")");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
} catch (NoSuchFieldException e5) {
|
||||||
|
// no way to access property - throw appropriate exception
|
||||||
|
throw new NoSuchPropertyException("No accessor method or field found for"
|
||||||
|
+ " property with name " + name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Class getterType = mGetter.getReturnType();
|
||||||
|
// Check to make sure our getter type matches our valueType
|
||||||
|
if (!typesMatch(valueType, getterType)) {
|
||||||
|
throw new NoSuchPropertyException("Underlying type (" + getterType + ") " +
|
||||||
|
"does not match Property type (" + valueType + ")");
|
||||||
|
}
|
||||||
|
String setterName = PREFIX_SET + capitalizedName;
|
||||||
|
try {
|
||||||
|
// mSetter = propertyHolder.getMethod(setterName, getterType);
|
||||||
|
// The native implementation uses JNI to do reflection, which allows access to private methods.
|
||||||
|
mSetter = propertyHolder.getDeclaredMethod(setterName, getterType);
|
||||||
|
mSetter.setAccessible(true);
|
||||||
|
} catch (NoSuchMethodException ignored) {
|
||||||
|
// Okay to not have a setter - just a readonly property
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility method to check whether the type of the underlying field/method on the target
|
||||||
|
* object matches the type of the Property. The extra checks for primitive types are because
|
||||||
|
* generics will force the Property type to be a class, whereas the type of the underlying
|
||||||
|
* method/field will probably be a primitive type instead. Accept float as matching Float,
|
||||||
|
* etc.
|
||||||
|
*/
|
||||||
|
private boolean typesMatch(Class<V> valueType, Class getterType) {
|
||||||
|
if (getterType != valueType) {
|
||||||
|
if (getterType.isPrimitive()) {
|
||||||
|
return (getterType == float.class && valueType == Float.class) ||
|
||||||
|
(getterType == int.class && valueType == Integer.class) ||
|
||||||
|
(getterType == boolean.class && valueType == Boolean.class) ||
|
||||||
|
(getterType == long.class && valueType == Long.class) ||
|
||||||
|
(getterType == double.class && valueType == Double.class) ||
|
||||||
|
(getterType == short.class && valueType == Short.class) ||
|
||||||
|
(getterType == byte.class && valueType == Byte.class) ||
|
||||||
|
(getterType == char.class && valueType == Character.class);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void set(T object, V value) {
|
||||||
|
if (mSetter != null) {
|
||||||
|
try {
|
||||||
|
mSetter.invoke(object, value);
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
throw new AssertionError();
|
||||||
|
} catch (InvocationTargetException e) {
|
||||||
|
throw new RuntimeException(e.getCause());
|
||||||
|
}
|
||||||
|
} else if (mField != null) {
|
||||||
|
try {
|
||||||
|
mField.set(object, value);
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new UnsupportedOperationException("Property " + getName() +" is read-only");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public V get(T object) {
|
||||||
|
if (mGetter != null) {
|
||||||
|
try {
|
||||||
|
return (V) mGetter.invoke(object, (Object[])null);
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
throw new AssertionError();
|
||||||
|
} catch (InvocationTargetException e) {
|
||||||
|
throw new RuntimeException(e.getCause());
|
||||||
|
}
|
||||||
|
} else if (mField != null) {
|
||||||
|
try {
|
||||||
|
return (V) mField.get(object);
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Should not get here: there should always be a non-null getter or field
|
||||||
|
throw new AssertionError();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns false if there is no setter or public field underlying this Property.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean isReadOnly() {
|
||||||
|
return (mSetter == null && mField == null);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2010 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.telegram.ui.Animation;
|
||||||
|
|
||||||
|
public interface TypeEvaluator<T> {
|
||||||
|
public T evaluate(float fraction, T startValue, T endValue);
|
||||||
|
}
|
@ -0,0 +1,675 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2010 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.telegram.ui.Animation;
|
||||||
|
|
||||||
|
import android.os.Looper;
|
||||||
|
import android.util.AndroidRuntimeException;
|
||||||
|
import android.view.animation.AccelerateDecelerateInterpolator;
|
||||||
|
import android.view.animation.AnimationUtils;
|
||||||
|
import android.view.animation.Interpolator;
|
||||||
|
import android.view.animation.LinearInterpolator;
|
||||||
|
|
||||||
|
import org.telegram.android.AndroidUtilities;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
public class ValueAnimator extends Animator10 {
|
||||||
|
|
||||||
|
private static float sDurationScale = 1.0f;
|
||||||
|
static final int STOPPED = 0;
|
||||||
|
static final int RUNNING = 1;
|
||||||
|
static final int SEEKED = 2;
|
||||||
|
|
||||||
|
long mStartTime;
|
||||||
|
long mSeekTime = -1;
|
||||||
|
private long mPauseTime;
|
||||||
|
private boolean mResumed = false;
|
||||||
|
protected static ThreadLocal<AnimationHandler> sAnimationHandler = new ThreadLocal<AnimationHandler>();
|
||||||
|
private static final Interpolator sDefaultInterpolator = new AccelerateDecelerateInterpolator();
|
||||||
|
private boolean mPlayingBackwards = false;
|
||||||
|
private int mCurrentIteration = 0;
|
||||||
|
private float mCurrentFraction = 0f;
|
||||||
|
private boolean mStartedDelay = false;
|
||||||
|
private long mDelayStartTime;
|
||||||
|
int mPlayingState = STOPPED;
|
||||||
|
private boolean mRunning = false;
|
||||||
|
private boolean mStarted = false;
|
||||||
|
private boolean mStartListenersCalled = false;
|
||||||
|
boolean mInitialized = false;
|
||||||
|
|
||||||
|
private long mDuration = (long)(300 * sDurationScale);
|
||||||
|
private long mUnscaledDuration = 300;
|
||||||
|
private long mStartDelay = 0;
|
||||||
|
private long mUnscaledStartDelay = 0;
|
||||||
|
private int mRepeatCount = 0;
|
||||||
|
private int mRepeatMode = RESTART;
|
||||||
|
private Interpolator mInterpolator = sDefaultInterpolator;
|
||||||
|
private ArrayList<AnimatorUpdateListener> mUpdateListeners = null;
|
||||||
|
PropertyValuesHolder[] mValues;
|
||||||
|
HashMap<String, PropertyValuesHolder> mValuesMap;
|
||||||
|
|
||||||
|
public static final int RESTART = 1;
|
||||||
|
public static final int REVERSE = 2;
|
||||||
|
public static final int INFINITE = -1;
|
||||||
|
|
||||||
|
public static void setDurationScale(float durationScale) {
|
||||||
|
sDurationScale = durationScale;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float getDurationScale() {
|
||||||
|
return sDurationScale;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValueAnimator() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ValueAnimator ofInt(int... values) {
|
||||||
|
ValueAnimator anim = new ValueAnimator();
|
||||||
|
anim.setIntValues(values);
|
||||||
|
return anim;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ValueAnimator ofFloat(float... values) {
|
||||||
|
ValueAnimator anim = new ValueAnimator();
|
||||||
|
anim.setFloatValues(values);
|
||||||
|
return anim;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ValueAnimator ofPropertyValuesHolder(PropertyValuesHolder... values) {
|
||||||
|
ValueAnimator anim = new ValueAnimator();
|
||||||
|
anim.setValues(values);
|
||||||
|
return anim;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ValueAnimator ofObject(TypeEvaluator evaluator, Object... values) {
|
||||||
|
ValueAnimator anim = new ValueAnimator();
|
||||||
|
anim.setObjectValues(values);
|
||||||
|
anim.setEvaluator(evaluator);
|
||||||
|
return anim;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIntValues(int... values) {
|
||||||
|
if (values == null || values.length == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (mValues == null || mValues.length == 0) {
|
||||||
|
setValues(PropertyValuesHolder.ofInt("", values));
|
||||||
|
} else {
|
||||||
|
PropertyValuesHolder valuesHolder = mValues[0];
|
||||||
|
valuesHolder.setIntValues(values);
|
||||||
|
}
|
||||||
|
mInitialized = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFloatValues(float... values) {
|
||||||
|
if (values == null || values.length == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (mValues == null || mValues.length == 0) {
|
||||||
|
setValues(PropertyValuesHolder.ofFloat("", values));
|
||||||
|
} else {
|
||||||
|
PropertyValuesHolder valuesHolder = mValues[0];
|
||||||
|
valuesHolder.setFloatValues(values);
|
||||||
|
}
|
||||||
|
mInitialized = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setObjectValues(Object... values) {
|
||||||
|
if (values == null || values.length == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (mValues == null || mValues.length == 0) {
|
||||||
|
setValues(PropertyValuesHolder.ofObject("", null, values));
|
||||||
|
} else {
|
||||||
|
PropertyValuesHolder valuesHolder = mValues[0];
|
||||||
|
valuesHolder.setObjectValues(values);
|
||||||
|
}
|
||||||
|
mInitialized = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValues(PropertyValuesHolder... values) {
|
||||||
|
int numValues = values.length;
|
||||||
|
mValues = values;
|
||||||
|
mValuesMap = new HashMap<String, PropertyValuesHolder>(numValues);
|
||||||
|
for (PropertyValuesHolder valuesHolder : values) {
|
||||||
|
mValuesMap.put(valuesHolder.getPropertyName(), valuesHolder);
|
||||||
|
}
|
||||||
|
mInitialized = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PropertyValuesHolder[] getValues() {
|
||||||
|
return mValues;
|
||||||
|
}
|
||||||
|
|
||||||
|
void initAnimation() {
|
||||||
|
if (!mInitialized) {
|
||||||
|
int numValues = mValues.length;
|
||||||
|
for (PropertyValuesHolder mValue : mValues) {
|
||||||
|
mValue.init();
|
||||||
|
}
|
||||||
|
mInitialized = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValueAnimator setDuration(long duration) {
|
||||||
|
if (duration < 0) {
|
||||||
|
throw new IllegalArgumentException("Animators cannot have negative duration: " + duration);
|
||||||
|
}
|
||||||
|
mUnscaledDuration = duration;
|
||||||
|
mDuration = (long)(duration * sDurationScale);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getDuration() {
|
||||||
|
return mUnscaledDuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCurrentPlayTime(long playTime) {
|
||||||
|
initAnimation();
|
||||||
|
long currentTime = AnimationUtils.currentAnimationTimeMillis();
|
||||||
|
if (mPlayingState != RUNNING) {
|
||||||
|
mSeekTime = playTime;
|
||||||
|
mPlayingState = SEEKED;
|
||||||
|
}
|
||||||
|
mStartTime = currentTime - playTime;
|
||||||
|
doAnimationFrame(currentTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getCurrentPlayTime() {
|
||||||
|
if (!mInitialized || mPlayingState == STOPPED) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return AnimationUtils.currentAnimationTimeMillis() - mStartTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
protected static class AnimationHandler implements Runnable {
|
||||||
|
|
||||||
|
protected final ArrayList<ValueAnimator> mAnimations = new ArrayList<ValueAnimator>();
|
||||||
|
private final ArrayList<ValueAnimator> mTmpAnimations = new ArrayList<ValueAnimator>();
|
||||||
|
protected final ArrayList<ValueAnimator> mPendingAnimations = new ArrayList<ValueAnimator>();
|
||||||
|
protected final ArrayList<ValueAnimator> mDelayedAnims = new ArrayList<ValueAnimator>();
|
||||||
|
private final ArrayList<ValueAnimator> mEndingAnims = new ArrayList<ValueAnimator>();
|
||||||
|
private final ArrayList<ValueAnimator> mReadyAnims = new ArrayList<ValueAnimator>();
|
||||||
|
|
||||||
|
private boolean mAnimationScheduled;
|
||||||
|
|
||||||
|
public void start() {
|
||||||
|
scheduleAnimation();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doAnimationFrame(long frameTime) {
|
||||||
|
while (mPendingAnimations.size() > 0) {
|
||||||
|
ArrayList<ValueAnimator> pendingCopy = (ArrayList<ValueAnimator>) mPendingAnimations.clone();
|
||||||
|
mPendingAnimations.clear();
|
||||||
|
int count = pendingCopy.size();
|
||||||
|
for (ValueAnimator anim : pendingCopy) {
|
||||||
|
if (anim.mStartDelay == 0) {
|
||||||
|
anim.startAnimation(this);
|
||||||
|
} else {
|
||||||
|
mDelayedAnims.add(anim);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int numDelayedAnims = mDelayedAnims.size();
|
||||||
|
for (ValueAnimator anim : mDelayedAnims) {
|
||||||
|
if (anim.delayedAnimationFrame(frameTime)) {
|
||||||
|
mReadyAnims.add(anim);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int numReadyAnims = mReadyAnims.size();
|
||||||
|
if (numReadyAnims > 0) {
|
||||||
|
for (ValueAnimator anim : mReadyAnims) {
|
||||||
|
anim.startAnimation(this);
|
||||||
|
anim.mRunning = true;
|
||||||
|
mDelayedAnims.remove(anim);
|
||||||
|
}
|
||||||
|
mReadyAnims.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
int numAnims = mAnimations.size();
|
||||||
|
for (ValueAnimator mAnimation : mAnimations) {
|
||||||
|
mTmpAnimations.add(mAnimation);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < numAnims; ++i) {
|
||||||
|
ValueAnimator anim = mTmpAnimations.get(i);
|
||||||
|
if (mAnimations.contains(anim) && anim.doAnimationFrame(frameTime)) {
|
||||||
|
mEndingAnims.add(anim);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mTmpAnimations.clear();
|
||||||
|
if (mEndingAnims.size() > 0) {
|
||||||
|
for (ValueAnimator mEndingAnim : mEndingAnims) {
|
||||||
|
mEndingAnim.endAnimation(this);
|
||||||
|
}
|
||||||
|
mEndingAnims.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mAnimations.isEmpty() || !mDelayedAnims.isEmpty()) {
|
||||||
|
scheduleAnimation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
mAnimationScheduled = false;
|
||||||
|
doAnimationFrame(System.nanoTime() / 1000000);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void scheduleAnimation() {
|
||||||
|
if (!mAnimationScheduled) {
|
||||||
|
AndroidUtilities.runOnUIThread(this);
|
||||||
|
mAnimationScheduled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getStartDelay() {
|
||||||
|
return mUnscaledStartDelay;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStartDelay(long startDelay) {
|
||||||
|
this.mStartDelay = (long)(startDelay * sDurationScale);
|
||||||
|
mUnscaledStartDelay = startDelay;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getAnimatedValue() {
|
||||||
|
if (mValues != null && mValues.length > 0) {
|
||||||
|
return mValues[0].getAnimatedValue();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getAnimatedValue(String propertyName) {
|
||||||
|
PropertyValuesHolder valuesHolder = mValuesMap.get(propertyName);
|
||||||
|
if (valuesHolder != null) {
|
||||||
|
return valuesHolder.getAnimatedValue();
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRepeatCount(int value) {
|
||||||
|
mRepeatCount = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getRepeatCount() {
|
||||||
|
return mRepeatCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRepeatMode(int value) {
|
||||||
|
mRepeatMode = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getRepeatMode() {
|
||||||
|
return mRepeatMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addUpdateListener(AnimatorUpdateListener listener) {
|
||||||
|
if (mUpdateListeners == null) {
|
||||||
|
mUpdateListeners = new ArrayList<AnimatorUpdateListener>();
|
||||||
|
}
|
||||||
|
mUpdateListeners.add(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeAllUpdateListeners() {
|
||||||
|
if (mUpdateListeners == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mUpdateListeners.clear();
|
||||||
|
mUpdateListeners = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeUpdateListener(AnimatorUpdateListener listener) {
|
||||||
|
if (mUpdateListeners == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mUpdateListeners.remove(listener);
|
||||||
|
if (mUpdateListeners.size() == 0) {
|
||||||
|
mUpdateListeners = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setInterpolator(Interpolator value) {
|
||||||
|
if (value != null) {
|
||||||
|
mInterpolator = value;
|
||||||
|
} else {
|
||||||
|
mInterpolator = new LinearInterpolator();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Interpolator getInterpolator() {
|
||||||
|
return mInterpolator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEvaluator(TypeEvaluator value) {
|
||||||
|
if (value != null && mValues != null && mValues.length > 0) {
|
||||||
|
mValues[0].setEvaluator(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private void notifyStartListeners() {
|
||||||
|
if (mListeners != null && !mStartListenersCalled) {
|
||||||
|
ArrayList<AnimatorListener> tmpListeners = (ArrayList<AnimatorListener>) mListeners.clone();
|
||||||
|
int numListeners = tmpListeners.size();
|
||||||
|
for (AnimatorListener tmpListener : tmpListeners) {
|
||||||
|
tmpListener.onAnimationStart(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mStartListenersCalled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void start(boolean playBackwards) {
|
||||||
|
if (Looper.myLooper() == null) {
|
||||||
|
throw new AndroidRuntimeException("Animators may only be run on Looper threads");
|
||||||
|
}
|
||||||
|
mPlayingBackwards = playBackwards;
|
||||||
|
mCurrentIteration = 0;
|
||||||
|
mPlayingState = STOPPED;
|
||||||
|
mStarted = true;
|
||||||
|
mStartedDelay = false;
|
||||||
|
mPaused = false;
|
||||||
|
AnimationHandler animationHandler = getOrCreateAnimationHandler();
|
||||||
|
animationHandler.mPendingAnimations.add(this);
|
||||||
|
if (mStartDelay == 0) {
|
||||||
|
setCurrentPlayTime(0);
|
||||||
|
mPlayingState = STOPPED;
|
||||||
|
mRunning = true;
|
||||||
|
notifyStartListeners();
|
||||||
|
}
|
||||||
|
animationHandler.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void start() {
|
||||||
|
start(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Override
|
||||||
|
public void cancel() {
|
||||||
|
AnimationHandler handler = getOrCreateAnimationHandler();
|
||||||
|
if (mPlayingState != STOPPED || handler.mPendingAnimations.contains(this) || handler.mDelayedAnims.contains(this)) {
|
||||||
|
if ((mStarted || mRunning) && mListeners != null) {
|
||||||
|
if (!mRunning) {
|
||||||
|
notifyStartListeners();
|
||||||
|
}
|
||||||
|
ArrayList<AnimatorListener> tmpListeners = (ArrayList<AnimatorListener>) mListeners.clone();
|
||||||
|
for (AnimatorListener listener : tmpListeners) {
|
||||||
|
listener.onAnimationCancel(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
endAnimation(handler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void end() {
|
||||||
|
AnimationHandler handler = getOrCreateAnimationHandler();
|
||||||
|
if (!handler.mAnimations.contains(this) && !handler.mPendingAnimations.contains(this)) {
|
||||||
|
mStartedDelay = false;
|
||||||
|
startAnimation(handler);
|
||||||
|
mStarted = true;
|
||||||
|
} else if (!mInitialized) {
|
||||||
|
initAnimation();
|
||||||
|
}
|
||||||
|
animateValue(mPlayingBackwards ? 0f : 1f);
|
||||||
|
endAnimation(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void resume() {
|
||||||
|
if (mPaused) {
|
||||||
|
mResumed = true;
|
||||||
|
}
|
||||||
|
super.resume();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void pause() {
|
||||||
|
boolean previouslyPaused = mPaused;
|
||||||
|
super.pause();
|
||||||
|
if (!previouslyPaused && mPaused) {
|
||||||
|
mPauseTime = -1;
|
||||||
|
mResumed = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isRunning() {
|
||||||
|
return (mPlayingState == RUNNING || mRunning);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isStarted() {
|
||||||
|
return mStarted;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reverse() {
|
||||||
|
mPlayingBackwards = !mPlayingBackwards;
|
||||||
|
if (mPlayingState == RUNNING) {
|
||||||
|
long currentTime = AnimationUtils.currentAnimationTimeMillis();
|
||||||
|
long currentPlayTime = currentTime - mStartTime;
|
||||||
|
long timeLeft = mDuration - currentPlayTime;
|
||||||
|
mStartTime = currentTime - timeLeft;
|
||||||
|
} else if (mStarted) {
|
||||||
|
end();
|
||||||
|
} else {
|
||||||
|
start(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private void endAnimation(AnimationHandler handler) {
|
||||||
|
handler.mAnimations.remove(this);
|
||||||
|
handler.mPendingAnimations.remove(this);
|
||||||
|
handler.mDelayedAnims.remove(this);
|
||||||
|
mPlayingState = STOPPED;
|
||||||
|
mPaused = false;
|
||||||
|
if ((mStarted || mRunning) && mListeners != null) {
|
||||||
|
if (!mRunning) {
|
||||||
|
notifyStartListeners();
|
||||||
|
}
|
||||||
|
ArrayList<AnimatorListener> tmpListeners = (ArrayList<AnimatorListener>) mListeners.clone();
|
||||||
|
int numListeners = tmpListeners.size();
|
||||||
|
for (AnimatorListener tmpListener : tmpListeners) {
|
||||||
|
tmpListener.onAnimationEnd(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mRunning = false;
|
||||||
|
mStarted = false;
|
||||||
|
mStartListenersCalled = false;
|
||||||
|
mPlayingBackwards = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startAnimation(AnimationHandler handler) {
|
||||||
|
initAnimation();
|
||||||
|
handler.mAnimations.add(this);
|
||||||
|
if (mStartDelay > 0 && mListeners != null) {
|
||||||
|
notifyStartListeners();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean delayedAnimationFrame(long currentTime) {
|
||||||
|
if (!mStartedDelay) {
|
||||||
|
mStartedDelay = true;
|
||||||
|
mDelayStartTime = currentTime;
|
||||||
|
} else {
|
||||||
|
if (mPaused) {
|
||||||
|
if (mPauseTime < 0) {
|
||||||
|
mPauseTime = currentTime;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} else if (mResumed) {
|
||||||
|
mResumed = false;
|
||||||
|
if (mPauseTime > 0) {
|
||||||
|
mDelayStartTime += (currentTime - mPauseTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
long deltaTime = currentTime - mDelayStartTime;
|
||||||
|
if (deltaTime > mStartDelay) {
|
||||||
|
mStartTime = currentTime - (deltaTime - mStartDelay);
|
||||||
|
mPlayingState = RUNNING;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean animationFrame(long currentTime) {
|
||||||
|
boolean done = false;
|
||||||
|
switch (mPlayingState) {
|
||||||
|
case RUNNING:
|
||||||
|
case SEEKED:
|
||||||
|
float fraction = mDuration > 0 ? (float)(currentTime - mStartTime) / mDuration : 1f;
|
||||||
|
if (fraction >= 1f) {
|
||||||
|
if (mCurrentIteration < mRepeatCount || mRepeatCount == INFINITE) {
|
||||||
|
if (mListeners != null) {
|
||||||
|
int numListeners = mListeners.size();
|
||||||
|
for (AnimatorListener mListener : mListeners) {
|
||||||
|
mListener.onAnimationRepeat(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mRepeatMode == REVERSE) {
|
||||||
|
mPlayingBackwards = !mPlayingBackwards;
|
||||||
|
}
|
||||||
|
mCurrentIteration += (int)fraction;
|
||||||
|
fraction = fraction % 1f;
|
||||||
|
mStartTime += mDuration;
|
||||||
|
} else {
|
||||||
|
done = true;
|
||||||
|
fraction = Math.min(fraction, 1.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mPlayingBackwards) {
|
||||||
|
fraction = 1f - fraction;
|
||||||
|
}
|
||||||
|
animateValue(fraction);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return done;
|
||||||
|
}
|
||||||
|
|
||||||
|
final boolean doAnimationFrame(long frameTime) {
|
||||||
|
if (mPlayingState == STOPPED) {
|
||||||
|
mPlayingState = RUNNING;
|
||||||
|
if (mSeekTime < 0) {
|
||||||
|
mStartTime = frameTime;
|
||||||
|
} else {
|
||||||
|
mStartTime = frameTime - mSeekTime;
|
||||||
|
mSeekTime = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mPaused) {
|
||||||
|
if (mPauseTime < 0) {
|
||||||
|
mPauseTime = frameTime;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} else if (mResumed) {
|
||||||
|
mResumed = false;
|
||||||
|
if (mPauseTime > 0) {
|
||||||
|
mStartTime += (frameTime - mPauseTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
final long currentTime = Math.max(frameTime, mStartTime);
|
||||||
|
return animationFrame(currentTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getAnimatedFraction() {
|
||||||
|
return mCurrentFraction;
|
||||||
|
}
|
||||||
|
|
||||||
|
void animateValue(float fraction) {
|
||||||
|
fraction = mInterpolator.getInterpolation(fraction);
|
||||||
|
mCurrentFraction = fraction;
|
||||||
|
int numValues = mValues.length;
|
||||||
|
for (PropertyValuesHolder mValue : mValues) {
|
||||||
|
mValue.calculateValue(fraction);
|
||||||
|
}
|
||||||
|
if (mUpdateListeners != null) {
|
||||||
|
int numListeners = mUpdateListeners.size();
|
||||||
|
for (AnimatorUpdateListener mUpdateListener : mUpdateListeners) {
|
||||||
|
mUpdateListener.onAnimationUpdate(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ValueAnimator clone() {
|
||||||
|
final ValueAnimator anim = (ValueAnimator) super.clone();
|
||||||
|
if (mUpdateListeners != null) {
|
||||||
|
ArrayList<AnimatorUpdateListener> oldListeners = mUpdateListeners;
|
||||||
|
anim.mUpdateListeners = new ArrayList<AnimatorUpdateListener>();
|
||||||
|
int numListeners = oldListeners.size();
|
||||||
|
for (AnimatorUpdateListener oldListener : oldListeners) {
|
||||||
|
anim.mUpdateListeners.add(oldListener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
anim.mSeekTime = -1;
|
||||||
|
anim.mPlayingBackwards = false;
|
||||||
|
anim.mCurrentIteration = 0;
|
||||||
|
anim.mInitialized = false;
|
||||||
|
anim.mPlayingState = STOPPED;
|
||||||
|
anim.mStartedDelay = false;
|
||||||
|
PropertyValuesHolder[] oldValues = mValues;
|
||||||
|
if (oldValues != null) {
|
||||||
|
int numValues = oldValues.length;
|
||||||
|
anim.mValues = new PropertyValuesHolder[numValues];
|
||||||
|
anim.mValuesMap = new HashMap<String, PropertyValuesHolder>(numValues);
|
||||||
|
for (int i = 0; i < numValues; ++i) {
|
||||||
|
PropertyValuesHolder newValuesHolder = oldValues[i].clone();
|
||||||
|
anim.mValues[i] = newValuesHolder;
|
||||||
|
anim.mValuesMap.put(newValuesHolder.getPropertyName(), newValuesHolder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return anim;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static interface AnimatorUpdateListener {
|
||||||
|
void onAnimationUpdate(ValueAnimator animation);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getCurrentAnimationsCount() {
|
||||||
|
AnimationHandler handler = sAnimationHandler.get();
|
||||||
|
return handler != null ? handler.mAnimations.size() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void clearAllAnimations() {
|
||||||
|
AnimationHandler handler = sAnimationHandler.get();
|
||||||
|
if (handler != null) {
|
||||||
|
handler.mAnimations.clear();
|
||||||
|
handler.mPendingAnimations.clear();
|
||||||
|
handler.mDelayedAnims.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static AnimationHandler getOrCreateAnimationHandler() {
|
||||||
|
AnimationHandler handler = sAnimationHandler.get();
|
||||||
|
if (handler == null) {
|
||||||
|
handler = new AnimationHandler();
|
||||||
|
sAnimationHandler.set(handler);
|
||||||
|
}
|
||||||
|
return handler;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,349 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2012 Jake Wharton
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.telegram.ui.Animation;
|
||||||
|
|
||||||
|
import android.graphics.Camera;
|
||||||
|
import android.graphics.Matrix;
|
||||||
|
import android.graphics.RectF;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.animation.Animation;
|
||||||
|
import android.view.animation.Transformation;
|
||||||
|
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
|
import java.util.WeakHashMap;
|
||||||
|
|
||||||
|
public class View10 extends Animation {
|
||||||
|
|
||||||
|
public static boolean NEED_PROXY = Build.VERSION.SDK_INT < 11;
|
||||||
|
|
||||||
|
private static final WeakHashMap<View, View10> PROXIES = new WeakHashMap<View, View10>();
|
||||||
|
|
||||||
|
public static View10 wrap(View view) {
|
||||||
|
View10 proxy = PROXIES.get(view);
|
||||||
|
Animation animation = view.getAnimation();
|
||||||
|
if (proxy == null || proxy != animation && animation != null) {
|
||||||
|
proxy = new View10(view);
|
||||||
|
PROXIES.put(view, proxy);
|
||||||
|
} else if (animation == null) {
|
||||||
|
view.setAnimation(proxy);
|
||||||
|
}
|
||||||
|
return proxy;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final WeakReference<View> mView;
|
||||||
|
private final Camera mCamera = new Camera();
|
||||||
|
private boolean mHasPivot;
|
||||||
|
|
||||||
|
private float mAlpha = 1;
|
||||||
|
private float mPivotX;
|
||||||
|
private float mPivotY;
|
||||||
|
private float mRotationX;
|
||||||
|
private float mRotationY;
|
||||||
|
private float mRotationZ;
|
||||||
|
private float mScaleX = 1;
|
||||||
|
private float mScaleY = 1;
|
||||||
|
private float mTranslationX;
|
||||||
|
private float mTranslationY;
|
||||||
|
|
||||||
|
private final RectF mBefore = new RectF();
|
||||||
|
private final RectF mAfter = new RectF();
|
||||||
|
private final Matrix mTempMatrix = new Matrix();
|
||||||
|
|
||||||
|
private View10(View view) {
|
||||||
|
setDuration(0);
|
||||||
|
setFillAfter(true);
|
||||||
|
view.setAnimation(this);
|
||||||
|
mView = new WeakReference<View>(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getAlpha() {
|
||||||
|
return mAlpha;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAlpha(float alpha) {
|
||||||
|
if (mAlpha != alpha) {
|
||||||
|
mAlpha = alpha;
|
||||||
|
View view = mView.get();
|
||||||
|
if (view != null) {
|
||||||
|
view.invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getPivotX() {
|
||||||
|
return mPivotX;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPivotX(float pivotX) {
|
||||||
|
if (!mHasPivot || mPivotX != pivotX) {
|
||||||
|
prepareForUpdate();
|
||||||
|
mHasPivot = true;
|
||||||
|
mPivotX = pivotX;
|
||||||
|
invalidateAfterUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getPivotY() {
|
||||||
|
return mPivotY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPivotY(float pivotY) {
|
||||||
|
if (!mHasPivot || mPivotY != pivotY) {
|
||||||
|
prepareForUpdate();
|
||||||
|
mHasPivot = true;
|
||||||
|
mPivotY = pivotY;
|
||||||
|
invalidateAfterUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getRotation() {
|
||||||
|
return mRotationZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRotation(float rotation) {
|
||||||
|
if (mRotationZ != rotation) {
|
||||||
|
prepareForUpdate();
|
||||||
|
mRotationZ = rotation;
|
||||||
|
invalidateAfterUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getRotationX() {
|
||||||
|
return mRotationX;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRotationX(float rotationX) {
|
||||||
|
if (mRotationX != rotationX) {
|
||||||
|
prepareForUpdate();
|
||||||
|
mRotationX = rotationX;
|
||||||
|
invalidateAfterUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getRotationY() {
|
||||||
|
return mRotationY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRotationY(float rotationY) {
|
||||||
|
if (mRotationY != rotationY) {
|
||||||
|
prepareForUpdate();
|
||||||
|
mRotationY = rotationY;
|
||||||
|
invalidateAfterUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getScaleX() {
|
||||||
|
return mScaleX;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setScaleX(float scaleX) {
|
||||||
|
if (mScaleX != scaleX) {
|
||||||
|
prepareForUpdate();
|
||||||
|
mScaleX = scaleX;
|
||||||
|
invalidateAfterUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getScaleY() {
|
||||||
|
return mScaleY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setScaleY(float scaleY) {
|
||||||
|
if (mScaleY != scaleY) {
|
||||||
|
prepareForUpdate();
|
||||||
|
mScaleY = scaleY;
|
||||||
|
invalidateAfterUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getScrollX() {
|
||||||
|
View view = mView.get();
|
||||||
|
if (view == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return view.getScrollX();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setScrollX(int value) {
|
||||||
|
View view = mView.get();
|
||||||
|
if (view != null) {
|
||||||
|
view.scrollTo(value, view.getScrollY());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getScrollY() {
|
||||||
|
View view = mView.get();
|
||||||
|
if (view == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return view.getScrollY();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setScrollY(int value) {
|
||||||
|
View view = mView.get();
|
||||||
|
if (view != null) {
|
||||||
|
view.scrollTo(view.getScrollX(), value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getTranslationX() {
|
||||||
|
return mTranslationX;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTranslationX(float translationX) {
|
||||||
|
if (mTranslationX != translationX) {
|
||||||
|
prepareForUpdate();
|
||||||
|
mTranslationX = translationX;
|
||||||
|
invalidateAfterUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getTranslationY() {
|
||||||
|
return mTranslationY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTranslationY(float translationY) {
|
||||||
|
if (mTranslationY != translationY) {
|
||||||
|
prepareForUpdate();
|
||||||
|
mTranslationY = translationY;
|
||||||
|
invalidateAfterUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getX() {
|
||||||
|
View view = mView.get();
|
||||||
|
if (view == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return view.getLeft() + mTranslationX;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setX(float x) {
|
||||||
|
View view = mView.get();
|
||||||
|
if (view != null) {
|
||||||
|
setTranslationX(x - view.getLeft());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getY() {
|
||||||
|
View view = mView.get();
|
||||||
|
if (view == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return view.getTop() + mTranslationY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setY(float y) {
|
||||||
|
View view = mView.get();
|
||||||
|
if (view != null) {
|
||||||
|
setTranslationY(y - view.getTop());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void prepareForUpdate() {
|
||||||
|
View view = mView.get();
|
||||||
|
if (view != null) {
|
||||||
|
computeRect(mBefore, view);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void invalidateAfterUpdate() {
|
||||||
|
View view = mView.get();
|
||||||
|
if (view == null || view.getParent() == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final RectF after = mAfter;
|
||||||
|
computeRect(after, view);
|
||||||
|
after.union(mBefore);
|
||||||
|
|
||||||
|
((View) view.getParent()).invalidate(
|
||||||
|
(int) Math.floor(after.left),
|
||||||
|
(int) Math.floor(after.top),
|
||||||
|
(int) Math.ceil(after.right),
|
||||||
|
(int) Math.ceil(after.bottom));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void computeRect(final RectF r, View view) {
|
||||||
|
final float w = view.getWidth();
|
||||||
|
final float h = view.getHeight();
|
||||||
|
|
||||||
|
r.set(0, 0, w, h);
|
||||||
|
|
||||||
|
final Matrix m = mTempMatrix;
|
||||||
|
m.reset();
|
||||||
|
transformMatrix(m, view);
|
||||||
|
mTempMatrix.mapRect(r);
|
||||||
|
|
||||||
|
r.offset(view.getLeft(), view.getTop());
|
||||||
|
|
||||||
|
if (r.right < r.left) {
|
||||||
|
final float f = r.right;
|
||||||
|
r.right = r.left;
|
||||||
|
r.left = f;
|
||||||
|
}
|
||||||
|
if (r.bottom < r.top) {
|
||||||
|
final float f = r.top;
|
||||||
|
r.top = r.bottom;
|
||||||
|
r.bottom = f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void transformMatrix(Matrix m, View view) {
|
||||||
|
final float w = view.getWidth();
|
||||||
|
final float h = view.getHeight();
|
||||||
|
final boolean hasPivot = mHasPivot;
|
||||||
|
final float pX = hasPivot ? mPivotX : w / 2f;
|
||||||
|
final float pY = hasPivot ? mPivotY : h / 2f;
|
||||||
|
|
||||||
|
final float rX = mRotationX;
|
||||||
|
final float rY = mRotationY;
|
||||||
|
final float rZ = mRotationZ;
|
||||||
|
if ((rX != 0) || (rY != 0) || (rZ != 0)) {
|
||||||
|
final Camera camera = mCamera;
|
||||||
|
camera.save();
|
||||||
|
camera.rotateX(rX);
|
||||||
|
camera.rotateY(rY);
|
||||||
|
camera.rotateZ(-rZ);
|
||||||
|
camera.getMatrix(m);
|
||||||
|
camera.restore();
|
||||||
|
m.preTranslate(-pX, -pY);
|
||||||
|
m.postTranslate(pX, pY);
|
||||||
|
}
|
||||||
|
|
||||||
|
final float sX = mScaleX;
|
||||||
|
final float sY = mScaleY;
|
||||||
|
if ((sX != 1.0f) || (sY != 1.0f)) {
|
||||||
|
m.postScale(sX, sY);
|
||||||
|
final float sPX = -(pX / w) * ((sX * w) - w);
|
||||||
|
final float sPY = -(pY / h) * ((sY * h) - h);
|
||||||
|
m.postTranslate(sPX, sPY);
|
||||||
|
}
|
||||||
|
|
||||||
|
m.postTranslate(mTranslationX, mTranslationY);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void applyTransformation(float interpolatedTime, Transformation t) {
|
||||||
|
View view = mView.get();
|
||||||
|
if (view != null) {
|
||||||
|
t.setAlpha(mAlpha);
|
||||||
|
transformMatrix(t.getMatrix(), view);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,112 @@
|
|||||||
|
/*
|
||||||
|
* This is the source code of Telegram for Android v. 1.7.x.
|
||||||
|
* It is licensed under GNU GPL v. 2 or later.
|
||||||
|
* You should have received a copy of the license in this archive (see LICENSE).
|
||||||
|
*
|
||||||
|
* Copyright Nikolai Kudashov, 2013-2014.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.telegram.ui.AnimationCompat;
|
||||||
|
|
||||||
|
import android.animation.Animator;
|
||||||
|
import android.animation.AnimatorListenerAdapter;
|
||||||
|
|
||||||
|
import org.telegram.ui.Animation.Animator10;
|
||||||
|
import org.telegram.ui.Animation.AnimatorListenerAdapter10;
|
||||||
|
import org.telegram.ui.Animation.View10;
|
||||||
|
|
||||||
|
public class AnimatorListenerAdapterProxy {
|
||||||
|
protected Object animatorListenerAdapter;
|
||||||
|
|
||||||
|
public AnimatorListenerAdapterProxy() {
|
||||||
|
if (View10.NEED_PROXY) {
|
||||||
|
animatorListenerAdapter = new AnimatorListenerAdapter10() {
|
||||||
|
@Override
|
||||||
|
public void onAnimationCancel(Animator10 animation) {
|
||||||
|
AnimatorListenerAdapterProxy.this.onAnimationCancel(animation);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAnimationEnd(Animator10 animation) {
|
||||||
|
AnimatorListenerAdapterProxy.this.onAnimationEnd(animation);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAnimationRepeat(Animator10 animation) {
|
||||||
|
AnimatorListenerAdapterProxy.this.onAnimationRepeat(animation);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAnimationStart(Animator10 animation) {
|
||||||
|
AnimatorListenerAdapterProxy.this.onAnimationStart(animation);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAnimationPause(Animator10 animation) {
|
||||||
|
AnimatorListenerAdapterProxy.this.onAnimationPause(animation);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAnimationResume(Animator10 animation) {
|
||||||
|
AnimatorListenerAdapterProxy.this.onAnimationResume(animation);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
animatorListenerAdapter = new AnimatorListenerAdapter() {
|
||||||
|
@Override
|
||||||
|
public void onAnimationCancel(Animator animation) {
|
||||||
|
AnimatorListenerAdapterProxy.this.onAnimationCancel(animation);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAnimationEnd(Animator animation) {
|
||||||
|
AnimatorListenerAdapterProxy.this.onAnimationEnd(animation);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAnimationRepeat(Animator animation) {
|
||||||
|
AnimatorListenerAdapterProxy.this.onAnimationRepeat(animation);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAnimationStart(Animator animation) {
|
||||||
|
AnimatorListenerAdapterProxy.this.onAnimationStart(animation);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAnimationPause(Animator animation) {
|
||||||
|
AnimatorListenerAdapterProxy.this.onAnimationPause(animation);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAnimationResume(Animator animation) {
|
||||||
|
AnimatorListenerAdapterProxy.this.onAnimationResume(animation);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onAnimationCancel(Object animation) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onAnimationEnd(Object animation) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onAnimationRepeat(Object animation) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onAnimationStart(Object animation) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onAnimationPause(Object animation) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onAnimationResume(Object animation) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,128 @@
|
|||||||
|
/*
|
||||||
|
* This is the source code of Telegram for Android v. 1.7.x.
|
||||||
|
* It is licensed under GNU GPL v. 2 or later.
|
||||||
|
* You should have received a copy of the license in this archive (see LICENSE).
|
||||||
|
*
|
||||||
|
* Copyright Nikolai Kudashov, 2013-2014.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.telegram.ui.AnimationCompat;
|
||||||
|
|
||||||
|
import android.animation.Animator;
|
||||||
|
import android.animation.AnimatorListenerAdapter;
|
||||||
|
import android.animation.AnimatorSet;
|
||||||
|
import android.view.animation.Interpolator;
|
||||||
|
|
||||||
|
import org.telegram.ui.Animation.Animator10;
|
||||||
|
import org.telegram.ui.Animation.AnimatorListenerAdapter10;
|
||||||
|
import org.telegram.ui.Animation.AnimatorSet10;
|
||||||
|
import org.telegram.ui.Animation.View10;
|
||||||
|
|
||||||
|
import java.lang.reflect.Array;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class AnimatorSetProxy {
|
||||||
|
|
||||||
|
private Object animatorSet;
|
||||||
|
|
||||||
|
public static <T, U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
|
||||||
|
return copyOfRange(original, 0, newLength, newType);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static <T, U> T[] copyOfRange(U[] original, int start, int end, Class<? extends T[]> newType) {
|
||||||
|
if (start > end) {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
int originalLength = original.length;
|
||||||
|
if (start < 0 || start > originalLength) {
|
||||||
|
throw new ArrayIndexOutOfBoundsException();
|
||||||
|
}
|
||||||
|
int resultLength = end - start;
|
||||||
|
int copyLength = Math.min(resultLength, originalLength - start);
|
||||||
|
T[] result = (T[]) Array.newInstance(newType.getComponentType(), resultLength);
|
||||||
|
System.arraycopy(original, start, result, 0, copyLength);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AnimatorSetProxy() {
|
||||||
|
if (View10.NEED_PROXY) {
|
||||||
|
animatorSet = new AnimatorSet10();
|
||||||
|
} else {
|
||||||
|
animatorSet = new AnimatorSet();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public void playTogether(Object... items) {
|
||||||
|
if (View10.NEED_PROXY) {
|
||||||
|
Animator10[] animators = copyOf(items, items.length, Animator10[].class);
|
||||||
|
((AnimatorSet10) animatorSet).playTogether(animators);
|
||||||
|
} else {
|
||||||
|
Animator[] animators = copyOf(items, items.length, Animator[].class);
|
||||||
|
((AnimatorSet) animatorSet).playTogether(animators);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void playTogether(ArrayList<Object> items) {
|
||||||
|
if (View10.NEED_PROXY) {
|
||||||
|
ArrayList<Animator10> animators = new ArrayList<Animator10>();
|
||||||
|
for (Object obj : items) {
|
||||||
|
animators.add((Animator10)obj);
|
||||||
|
}
|
||||||
|
((AnimatorSet10) animatorSet).playTogether(animators);
|
||||||
|
} else {
|
||||||
|
ArrayList<Animator> animators = new ArrayList<Animator>();
|
||||||
|
for (Object obj : items) {
|
||||||
|
animators.add((Animator)obj);
|
||||||
|
}
|
||||||
|
((AnimatorSet) animatorSet).playTogether(animators);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public AnimatorSetProxy setDuration(long duration) {
|
||||||
|
if (View10.NEED_PROXY) {
|
||||||
|
((AnimatorSet10) animatorSet).setDuration(duration);
|
||||||
|
} else {
|
||||||
|
((AnimatorSet) animatorSet).setDuration(duration);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void start() {
|
||||||
|
if (View10.NEED_PROXY) {
|
||||||
|
((AnimatorSet10) animatorSet).start();
|
||||||
|
} else {
|
||||||
|
((AnimatorSet) animatorSet).start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cancel() {
|
||||||
|
if (View10.NEED_PROXY) {
|
||||||
|
((AnimatorSet10) animatorSet).cancel();
|
||||||
|
} else {
|
||||||
|
((AnimatorSet) animatorSet).cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addListener(AnimatorListenerAdapterProxy listener) {
|
||||||
|
if (View10.NEED_PROXY) {
|
||||||
|
((AnimatorSet10) animatorSet).addListener((AnimatorListenerAdapter10) listener.animatorListenerAdapter);
|
||||||
|
} else {
|
||||||
|
((AnimatorSet) animatorSet).addListener((AnimatorListenerAdapter) listener.animatorListenerAdapter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInterpolator(Interpolator interpolator) {
|
||||||
|
if (View10.NEED_PROXY) {
|
||||||
|
((AnimatorSet10) animatorSet).setInterpolator(interpolator);
|
||||||
|
} else {
|
||||||
|
((AnimatorSet) animatorSet).setInterpolator(interpolator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
return animatorSet == o;
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user