Commit dd679bd7 authored by DrKLO's avatar DrKLO

Update to 4.1.1

parent 6a1cf64f
......@@ -9,15 +9,17 @@ configurations {
}
dependencies {
compile 'com.google.android.gms:play-services-gcm:10.2.0'
compile 'com.google.android.gms:play-services-maps:10.2.0'
compile 'com.google.android.gms:play-services-vision:10.2.0'
compile 'com.android.support:support-core-ui:25.3.0'
compile 'com.android.support:support-compat:25.3.0'
compile 'com.android.support:support-core-utils:25.3.0'
compile 'com.android.support:support-v13:25.3.0'
compile 'com.android.support:palette-v7:25.3.0'
compile 'net.hockeyapp.android:HockeySDK:4.1.2'
compile 'com.google.android.gms:play-services-gcm:11.0.1'
compile 'com.google.android.gms:play-services-maps:11.0.1'
compile 'com.google.android.gms:play-services-vision:11.0.1'
compile 'com.google.android.gms:play-services-wallet:11.0.1'
compile 'com.google.android.gms:play-services-wearable:11.0.1'
compile 'com.android.support:support-core-ui:25.3.1'
compile 'com.android.support:support-compat:25.3.1'
compile 'com.android.support:support-core-utils:25.3.1'
compile 'com.android.support:support-v13:25.3.1'
compile 'com.android.support:palette-v7:25.3.1'
compile 'net.hockeyapp.android:HockeySDK:4.1.3'
compile 'com.googlecode.mp4parser:isoparser:1.0.6'
compile 'com.stripe:stripe-android:2.0.2'
}
......@@ -88,7 +90,7 @@ android {
}
}
defaultConfig.versionCode = 957
defaultConfig.versionCode = 1030
sourceSets.debug {
manifest.srcFile 'config/debug/AndroidManifest.xml'
......@@ -160,7 +162,7 @@ android {
defaultConfig {
minSdkVersion 14
targetSdkVersion 25
versionName "3.18.0"
versionName "4.1.1"
externalNativeBuild {
ndkBuild {
......
......@@ -22,6 +22,7 @@
<application
android:allowBackup="false"
android:icon="@drawable/ic_launcher"
android:roundIcon="@drawable/ic_launcher"
android:label="@string/AppNameBeta"
android:theme="@style/Theme.TMessages.Start"
android:name=".ApplicationLoader"
......
......@@ -25,6 +25,7 @@
<application
android:allowBackup="false"
android:icon="@drawable/ic_launcher"
android:roundIcon="@drawable/ic_launcher"
android:label="@string/AppNameBeta"
android:theme="@style/Theme.TMessages.Start"
android:name=".ApplicationLoader"
......
......@@ -6,6 +6,7 @@
<application
android:allowBackup="false"
android:icon="@drawable/ic_launcher"
android:roundIcon="@drawable/ic_launcher"
android:label="@string/AppName"
android:theme="@style/Theme.TMessages.Start"
android:name=".ApplicationLoader"
......
......@@ -22,6 +22,7 @@
<application
android:allowBackup="false"
android:icon="@drawable/ic_launcher"
android:roundIcon="@drawable/ic_launcher"
android:label="@string/AppName"
android:theme="@style/Theme.TMessages.Start"
android:name=".ApplicationLoader"
......
......@@ -25,6 +25,7 @@
<application
android:allowBackup="false"
android:icon="@drawable/ic_launcher"
android:roundIcon="@drawable/ic_launcher"
android:label="@string/AppName"
android:theme="@style/Theme.TMessages.Start"
android:name=".ApplicationLoader"
......
......@@ -108,17 +108,9 @@ include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := WebRtcAec
LOCAL_SRC_FILES := ./libtgvoip/external/libWebRtcAec_android_$(TARGET_ARCH_ABI).a
include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := voip
LOCAL_CPPFLAGS := -Wall -std=c++11 -DANDROID -finline-functions -ffast-math -Os -fno-strict-aliasing -O3
LOCAL_CFLAGS := -O3 -DUSE_KISS_FFT -fexceptions
LOCAL_CPPFLAGS := -Wall -std=c++11 -DANDROID -finline-functions -ffast-math -Os -fno-strict-aliasing -O3 -frtti -D__STDC_LIMIT_MACROS
LOCAL_CFLAGS := -O3 -DUSE_KISS_FFT -fexceptions -DWEBRTC_APM_DEBUG_DUMP=0 -DWEBRTC_POSIX -D__STDC_LIMIT_MACROS
ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
# LOCAL_CPPFLAGS += -mfloat-abi=softfp -mfpu=neon
......@@ -138,7 +130,7 @@ endif
MY_DIR := libtgvoip
LOCAL_C_INCLUDES := jni/opus/include jni/boringssl/include/
LOCAL_C_INCLUDES := jni/opus/include jni/boringssl/include/ jni/libtgvoip/webrtc_dsp/
LOCAL_SRC_FILES := \
./libtgvoip/logging.cpp \
......@@ -160,7 +152,113 @@ LOCAL_SRC_FILES := \
./libtgvoip/os/android/AudioOutputAndroid.cpp \
./libtgvoip/EchoCanceller.cpp \
./libtgvoip/CongestionControl.cpp \
./libtgvoip/VoIPServerConfig.cpp
./libtgvoip/VoIPServerConfig.cpp \
./libtgvoip/audio/Resampler.cpp \
./libtgvoip/NetworkSocket.cpp \
./libtgvoip/os/posix/NetworkSocketPosix.cpp
# WebRTC signal processing
LOCAL_SRC_FILES += \
./libtgvoip/webrtc_dsp/webrtc/common_audio/ring_buffer.c \
./libtgvoip/webrtc_dsp/webrtc/common_audio/signal_processing/auto_corr_to_refl_coef.c \
./libtgvoip/webrtc_dsp/webrtc/common_audio/signal_processing/auto_correlation.c \
./libtgvoip/webrtc_dsp/webrtc/common_audio/signal_processing/complex_bit_reverse.c \
./libtgvoip/webrtc_dsp/webrtc/common_audio/signal_processing/complex_fft.c \
./libtgvoip/webrtc_dsp/webrtc/common_audio/signal_processing/copy_set_operations.c \
./libtgvoip/webrtc_dsp/webrtc/common_audio/signal_processing/cross_correlation.c \
./libtgvoip/webrtc_dsp/webrtc/common_audio/signal_processing/division_operations.c \
./libtgvoip/webrtc_dsp/webrtc/common_audio/signal_processing/dot_product_with_scale.c \
./libtgvoip/webrtc_dsp/webrtc/common_audio/signal_processing/downsample_fast.c \
./libtgvoip/webrtc_dsp/webrtc/common_audio/signal_processing/energy.c \
./libtgvoip/webrtc_dsp/webrtc/common_audio/signal_processing/filter_ar.c \
./libtgvoip/webrtc_dsp/webrtc/common_audio/signal_processing/filter_ar_fast_q12.c \
./libtgvoip/webrtc_dsp/webrtc/common_audio/signal_processing/filter_ma_fast_q12.c \
./libtgvoip/webrtc_dsp/webrtc/common_audio/signal_processing/get_hanning_window.c \
./libtgvoip/webrtc_dsp/webrtc/common_audio/signal_processing/get_scaling_square.c \
./libtgvoip/webrtc_dsp/webrtc/common_audio/signal_processing/ilbc_specific_functions.c \
./libtgvoip/webrtc_dsp/webrtc/common_audio/signal_processing/levinson_durbin.c \
./libtgvoip/webrtc_dsp/webrtc/common_audio/signal_processing/lpc_to_refl_coef.c \
./libtgvoip/webrtc_dsp/webrtc/common_audio/signal_processing/min_max_operations.c \
./libtgvoip/webrtc_dsp/webrtc/common_audio/signal_processing/randomization_functions.c \
./libtgvoip/webrtc_dsp/webrtc/common_audio/signal_processing/real_fft.c \
./libtgvoip/webrtc_dsp/webrtc/common_audio/signal_processing/refl_coef_to_lpc.c \
./libtgvoip/webrtc_dsp/webrtc/common_audio/signal_processing/resample.c \
./libtgvoip/webrtc_dsp/webrtc/common_audio/signal_processing/resample_48khz.c \
./libtgvoip/webrtc_dsp/webrtc/common_audio/signal_processing/resample_by_2.c \
./libtgvoip/webrtc_dsp/webrtc/common_audio/signal_processing/resample_by_2_internal.c \
./libtgvoip/webrtc_dsp/webrtc/common_audio/signal_processing/resample_fractional.c \
./libtgvoip/webrtc_dsp/webrtc/common_audio/signal_processing/spl_init.c \
./libtgvoip/webrtc_dsp/webrtc/common_audio/signal_processing/spl_inl.c \
./libtgvoip/webrtc_dsp/webrtc/common_audio/signal_processing/spl_sqrt.c \
./libtgvoip/webrtc_dsp/webrtc/common_audio/signal_processing/spl_sqrt_floor.c \
./libtgvoip/webrtc_dsp/webrtc/common_audio/signal_processing/splitting_filter_impl.c \
./libtgvoip/webrtc_dsp/webrtc/common_audio/signal_processing/sqrt_of_one_minus_x_squared.c \
./libtgvoip/webrtc_dsp/webrtc/common_audio/signal_processing/vector_scaling_operations.c
LOCAL_SRC_FILES += \
./libtgvoip/webrtc_dsp/webrtc/base/checks.cc \
./libtgvoip/webrtc_dsp/webrtc/modules/audio_processing/aecm/aecm_core.cc \
./libtgvoip/webrtc_dsp/webrtc/modules/audio_processing/aecm/aecm_core_c.cc \
./libtgvoip/webrtc_dsp/webrtc/modules/audio_processing/aecm/echo_control_mobile.cc \
./libtgvoip/webrtc_dsp/webrtc/modules/audio_processing/utility/delay_estimator.cc \
./libtgvoip/webrtc_dsp/webrtc/modules/audio_processing/utility/delay_estimator_wrapper.cc \
./libtgvoip/webrtc_dsp/webrtc/modules/audio_processing/three_band_filter_bank.cc \
./libtgvoip/webrtc_dsp/webrtc/modules/audio_processing/splitting_filter.cc \
./libtgvoip/webrtc_dsp/webrtc/system_wrappers/source/cpu_features.cc \
./libtgvoip/webrtc_dsp/webrtc/common_audio/sparse_fir_filter.cc \
./libtgvoip/webrtc_dsp/webrtc/common_audio/channel_buffer.cc \
./libtgvoip/webrtc_dsp/webrtc/common_audio/audio_util.cc
#LOCAL_SRC_FILES += \
#./libtgvoip/webrtc_dsp/webrtc/modules/audio_processing/utility/block_mean_calculator.cc \
#./libtgvoip/webrtc_dsp/webrtc/modules/audio_processing/utility/ooura_fft.cc \
#./libtgvoip/webrtc_dsp/webrtc/modules/audio_processing/logging/apm_data_dumper.cc \
#./libtgvoip/webrtc_dsp/webrtc/modules/audio_processing/aec/aec_core.cc \
#./libtgvoip/webrtc_dsp/webrtc/modules/audio_processing/aec/aec_resampler.cc \
#./libtgvoip/webrtc_dsp/webrtc/modules/audio_processing/aec/echo_cancellation.cc \
#./libtgvoip/webrtc_dsp/webrtc/common_audio/wav_header.cc \
#./libtgvoip/webrtc_dsp/webrtc/common_audio/wav_file.cc \
#./libtgvoip/webrtc_dsp/webrtc/base/stringutils.cc
LOCAL_SRC_FILES += \
./libtgvoip/webrtc_dsp/webrtc/modules/audio_processing/ns/noise_suppression_x.c \
./libtgvoip/webrtc_dsp/webrtc/modules/audio_processing/ns/noise_suppression.c \
./libtgvoip/webrtc_dsp/webrtc/modules/audio_processing/ns/ns_core.c \
./libtgvoip/webrtc_dsp/webrtc/modules/audio_processing/ns/nsx_core_c.c \
./libtgvoip/webrtc_dsp/webrtc/modules/audio_processing/ns/nsx_core.c \
./libtgvoip/webrtc_dsp/webrtc/common_audio/fft4g.c
LOCAL_SRC_FILES += \
./libtgvoip/webrtc_dsp/webrtc/modules/audio_processing/agc/legacy/analog_agc.c \
./libtgvoip/webrtc_dsp/webrtc/modules/audio_processing/agc/legacy/digital_agc.c
ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
LOCAL_SRC_FILES += \
./libtgvoip/webrtc_dsp/webrtc/modules/audio_processing/aecm/aecm_core_neon.cc.neon \
./libtgvoip/webrtc_dsp/webrtc/common_audio/signal_processing/min_max_operations_neon.c.neon \
./libtgvoip/webrtc_dsp/webrtc/common_audio/signal_processing/downsample_fast_neon.c.neon \
./libtgvoip/webrtc_dsp/webrtc/common_audio/signal_processing/cross_correlation_neon.c.neon \
./libtgvoip/webrtc_dsp/webrtc/common_audio/signal_processing/filter_ar_fast_q12_armv7.S.neon
#LOCAL_SRC_FILES += \
#./libtgvoip/webrtc_dsp/webrtc/modules/audio_processing/aec/aec_core_neon.cc.neon
#./libtgvoip/webrtc_dsp/webrtc/modules/audio_processing/utility/ooura_fft_neon.cc.neon
LOCAL_SRC_FILES += \
./libtgvoip/webrtc_dsp/webrtc/modules/audio_processing/ns/nsx_core_neon.c.neon
#LOCAL_ARM_NEON := true
endif
ifeq ($(TARGET_ARCH_ABI),armeabi)
LOCAL_SRC_FILES += \
./libtgvoip/webrtc_dsp/webrtc/common_audio/signal_processing/complex_bit_reverse_arm.S \
./libtgvoip/webrtc_dsp/webrtc/common_audio/signal_processing/spl_sqrt_floor_arm.S
endif
#ifeq ($(TARGET_ARCH_ABI),x86)
#LOCAL_SRC_FILES += \
#./libtgvoip/webrtc_dsp/webrtc/modules/audio_processing/aec/aec_core_sse2.cc \
#./libtgvoip/webrtc_dsp/webrtc/modules/audio_processing/utility/ooura_fft_sse2.cc
#endif
include $(BUILD_STATIC_LIBRARY)
......@@ -295,13 +393,13 @@ include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_PRELINK_MODULE := false
LOCAL_MODULE := tmessages.26
LOCAL_MODULE := tmessages.27
LOCAL_CFLAGS := -w -std=c11 -Os -DNULL=0 -DSOCKLEN_T=socklen_t -DLOCALE_NOT_USED -D_LARGEFILE_SOURCE=1 -D_FILE_OFFSET_BITS=64
LOCAL_CFLAGS += -Drestrict='' -D__EMX__ -DOPUS_BUILD -DFIXED_POINT -DUSE_ALLOCA -DHAVE_LRINT -DHAVE_LRINTF -fno-math-errno
LOCAL_CFLAGS += -DANDROID_NDK -DDISABLE_IMPORTGL -fno-strict-aliasing -fprefetch-loop-arrays -DAVOID_TABLES -DANDROID_TILE_BASED_DECODE -DANDROID_ARMV6_IDCT -ffast-math -D__STDC_CONSTANT_MACROS
LOCAL_CPPFLAGS := -DBSD=1 -ffast-math -Os -funroll-loops -std=c++11
LOCAL_LDLIBS := -ljnigraphics -llog -lz -latomic -lOpenSLES
LOCAL_STATIC_LIBRARIES := webp sqlite tgnet breakpad avformat avcodec avutil voip WebRtcAec
LOCAL_LDLIBS := -ljnigraphics -llog -lz -latomic -lOpenSLES -lEGL -lGLESv2
LOCAL_STATIC_LIBRARIES := webp sqlite tgnet breakpad avformat avcodec avutil voip
LOCAL_SRC_FILES := \
./opus/src/opus.c \
......
This diff is collapsed.
......@@ -252,16 +252,27 @@ jint Java_org_telegram_ui_Components_AnimatedFileDrawable_getVideoFrame(JNIEnv *
//LOGD("decoded frame with w = %d, h = %d, format = %d", info->frame->width, info->frame->height, info->frame->format);
if (info->frame->format == AV_PIX_FMT_YUV420P || info->frame->format == AV_PIX_FMT_BGRA || info->frame->format == AV_PIX_FMT_YUVJ420P) {
jint *dataArr = env->GetIntArrayElements(data, 0);
int wantedWidth;
int wantedHeight;
if (dataArr != nullptr) {
wantedWidth = dataArr[0];
wantedHeight = dataArr[1];
dataArr[3] = (int) (1000 * info->frame->pkt_pts * av_q2d(info->video_stream->time_base));
env->ReleaseIntArrayElements(data, dataArr, 0);
} else {
AndroidBitmapInfo bitmapInfo;
AndroidBitmap_getInfo(env, bitmap, &bitmapInfo);
wantedWidth = bitmapInfo.width;
wantedHeight = bitmapInfo.height;
}
void *pixels;
if (AndroidBitmap_lockPixels(env, bitmap, &pixels) >= 0) {
if (info->frame->format == AV_PIX_FMT_YUV420P || info->frame->format == AV_PIX_FMT_YUVJ420P) {
//LOGD("y %d, u %d, v %d, width %d, height %d", info->frame->linesize[0], info->frame->linesize[2], info->frame->linesize[1], info->frame->width, info->frame->height);
libyuv::I420ToARGB(info->frame->data[0], info->frame->linesize[0], info->frame->data[2], info->frame->linesize[2], info->frame->data[1], info->frame->linesize[1], (uint8_t *) pixels, info->frame->width * 4, info->frame->width, info->frame->height);
if (wantedWidth == info->frame->width && wantedHeight == info->frame->height || wantedWidth == info->frame->height && wantedHeight == info->frame->width) {
libyuv::I420ToARGB(info->frame->data[0], info->frame->linesize[0], info->frame->data[2], info->frame->linesize[2], info->frame->data[1], info->frame->linesize[1], (uint8_t *) pixels, info->frame->width * 4, info->frame->width, info->frame->height);
}
} else if (info->frame->format == AV_PIX_FMT_BGRA) {
libyuv::ABGRToARGB(info->frame->data[0], info->frame->linesize[0], (uint8_t *) pixels, info->frame->width * 4, info->frame->width, info->frame->height);
}
......
......@@ -56,6 +56,22 @@ JNIEXPORT void Java_org_telegram_messenger_Utilities_aesIgeEncryption(JNIEnv *en
(*env)->ReleaseByteArrayElements(env, iv, ivBuff, 0);
}
JNIEXPORT jint Java_org_telegram_messenger_Utilities_aesCtrDecryption(JNIEnv *env, jclass class, jobject buffer, jbyteArray key, jbyteArray iv, int offset, int length) {
jbyte *what = (*env)->GetDirectBufferAddress(env, buffer) + offset;
unsigned char *keyBuff = (unsigned char *)(*env)->GetByteArrayElements(env, key, NULL);
unsigned char *ivBuff = (unsigned char *)(*env)->GetByteArrayElements(env, iv, NULL);
AES_KEY akey;
unsigned int num = 0;
uint8_t count[16];
memset(count, 0, 16);
AES_set_encrypt_key(keyBuff, 32 * 8, &akey);
AES_ctr128_encrypt(what, what, length, &akey, ivBuff, count, &num);
(*env)->ReleaseByteArrayElements(env, key, keyBuff, JNI_ABORT);
(*env)->ReleaseByteArrayElements(env, iv, ivBuff, JNI_ABORT);
return num;
}
JNIEXPORT jstring Java_org_telegram_messenger_Utilities_readlink(JNIEnv *env, jclass class, jstring path) {
static char buf[1000];
char *fileName = (*env)->GetStringUTFChars(env, path, NULL);
......
......@@ -50,6 +50,11 @@ TL_dcOption *TL_dcOption::TLdeserialize(NativeByteBuffer *stream, uint32_t const
void TL_dcOption::readParams(NativeByteBuffer *stream, bool &error) {
flags = stream->readInt32(&error);
ipv6 = (flags & 1) != 0;
media_only = (flags & 2) != 0;
tcpo_only = (flags & 4) != 0;
cdn = (flags & 8) != 0;
isStatic = (flags & 16) != 0;
id = stream->readInt32(&error);
ip_address = stream->readString(&error);
port = stream->readInt32(&error);
......@@ -57,12 +62,89 @@ void TL_dcOption::readParams(NativeByteBuffer *stream, bool &error) {
void TL_dcOption::serializeToStream(NativeByteBuffer *stream) {
stream->writeInt32(constructor);
flags = ipv6 ? (flags | 1) : (flags &~ 1);
flags = media_only ? (flags | 2) : (flags &~ 2);
flags = tcpo_only ? (flags | 4) : (flags &~ 4);
flags = cdn ? (flags | 8) : (flags &~ 8);
flags = isStatic ? (flags | 16) : (flags &~ 16);
stream->writeInt32(flags);
stream->writeInt32(id);
stream->writeString(ip_address);
stream->writeInt32(port);
}
TL_cdnPublicKey *TL_cdnPublicKey::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error) {
if (TL_cdnPublicKey::constructor != constructor) {
error = true;
DEBUG_E("can't parse magic %x in TL_cdnPublicKey", constructor);
return nullptr;
}
TL_cdnPublicKey *result = new TL_cdnPublicKey();
result->readParams(stream, error);
return result;
}
void TL_cdnPublicKey::readParams(NativeByteBuffer *stream, bool &error) {
dc_id = stream->readInt32(&error);
public_key = stream->readString(&error);
}
void TL_cdnPublicKey::serializeToStream(NativeByteBuffer *stream) {
stream->writeInt32(constructor);
stream->writeInt32(dc_id);
stream->writeString(public_key);
}
TL_cdnConfig *TL_cdnConfig::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error) {
if (TL_cdnConfig::constructor != constructor) {
error = true;
DEBUG_E("can't parse magic %x in TL_cdnConfig", constructor);
return nullptr;
}
TL_cdnConfig *result = new TL_cdnConfig();
result->readParams(stream, error);
return result;
}
void TL_cdnConfig::readParams(NativeByteBuffer *stream, bool &error) {
int magic = stream->readInt32(&error);
if (magic != 0x1cb5c415) {
error = true;
DEBUG_E("wrong Vector magic, got %x", magic);
return;
}
int count = stream->readInt32(&error);
for (int a = 0; a < count; a++) {
TL_cdnPublicKey *object = TL_cdnPublicKey::TLdeserialize(stream, stream->readUint32(&error), error);
if (object == nullptr) {
return;
}
public_keys.push_back(std::unique_ptr<TL_cdnPublicKey>(object));
}
}
void TL_cdnConfig::serializeToStream(NativeByteBuffer *stream) {
stream->writeInt32(constructor);
stream->writeInt32(0x1cb5c415);
int count = public_keys.size();
stream->writeInt32(count);
for (int a = 0; a < count; a++) {
public_keys[a]->serializeToStream(stream);
}
}
bool TL_help_getCdnConfig::isNeedLayer() {
return true;
}
TLObject *TL_help_getCdnConfig::deserializeResponse(NativeByteBuffer *stream, uint32_t constructor, bool &error) {
return TL_cdnConfig::TLdeserialize(stream, constructor, error);
}
void TL_help_getCdnConfig::serializeToStream(NativeByteBuffer *stream) {
stream->writeInt32(constructor);
}
TL_disabledFeature *TL_disabledFeature::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error) {
if (TL_disabledFeature::constructor != constructor) {
error = true;
......@@ -141,6 +223,12 @@ void TL_config::readParams(NativeByteBuffer *stream, bool &error) {
call_connect_timeout_ms = stream->readInt32(&error);
call_packet_timeout_ms = stream->readInt32(&error);
me_url_prefix = stream->readString(&error);
if ((flags & 4) != 0) {
suggested_lang_code = stream->readString(&error);
}
if ((flags & 4) != 0) {
lang_pack_version = stream->readInt32(&error);
}
magic = stream->readUint32(&error);
if (magic != 0x1cb5c415) {
error = true;
......@@ -195,6 +283,12 @@ void TL_config::serializeToStream(NativeByteBuffer *stream) {
stream->writeInt32(call_connect_timeout_ms);
stream->writeInt32(call_packet_timeout_ms);
stream->writeString(me_url_prefix);
if ((flags & 4) != 0) {
stream->writeString(suggested_lang_code);
}
if ((flags & 4) != 0) {
stream->writeInt32(lang_pack_version);
}
stream->writeInt32(0x1cb5c415);
count = (uint32_t) disabled_features.size();
stream->writeInt32(count);
......@@ -235,7 +329,7 @@ User *User::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &
case 0x200250ba:
result = new TL_userEmpty();
break;
case 0xd10d979a:
case 0x2e13f4c3:
result = new TL_user();
break;
default:
......@@ -289,6 +383,9 @@ void TL_user::readParams(NativeByteBuffer *stream, bool &error) {
if ((flags & 524288) != 0) {
bot_inline_placeholder = stream->readString(&error);
}
if ((flags & 4194304) != 0) {
lang_code = stream->readString(&error);
}
}
void TL_user::serializeToStream(NativeByteBuffer *stream) {
......@@ -325,6 +422,9 @@ void TL_user::serializeToStream(NativeByteBuffer *stream) {
if ((flags & 524288) != 0) {
stream->writeString(bot_inline_placeholder);
}
if ((flags & 4194304) != 0) {
stream->writeString(lang_code);
}
}
TL_auth_authorization *TL_auth_authorization::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error) {
......@@ -640,7 +740,7 @@ TL_upload_file::~TL_upload_file() {
}
void TL_upload_file::readParams(NativeByteBuffer *stream, bool &error) {
type = std::unique_ptr<storage_FileType>(storage_FileType::TLdeserialize(stream, stream->readInt32(&error), error));
type = std::unique_ptr<storage_FileType>(storage_FileType::TLdeserialize(stream, stream->readUint32(&error), error));
mtime = stream->readInt32(&error);
bytes = stream->readByteBuffer(true, &error);
}
......
......@@ -45,6 +45,11 @@ public:
static const uint32_t constructor = 0x5d8c6cc;
int32_t flags;
bool ipv6;
bool media_only;
bool tcpo_only;
bool cdn;
bool isStatic;
int32_t id;
std::string ip_address;
int32_t port;
......@@ -54,6 +59,41 @@ public:
void serializeToStream(NativeByteBuffer *stream);
};
class TL_cdnPublicKey : public TLObject {
public:
static const uint32_t constructor = 0xc982eaba;
int32_t dc_id;
std::string public_key;
static TL_cdnPublicKey *TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error);
void readParams(NativeByteBuffer *stream, bool &error);
void serializeToStream(NativeByteBuffer *stream);
};
class TL_cdnConfig : public TLObject {
public:
static const uint32_t constructor = 0x5725e40a;
std::vector<std::unique_ptr<TL_cdnPublicKey>> public_keys;
static TL_cdnConfig *TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error);
void readParams(NativeByteBuffer *stream, bool &error);
void serializeToStream(NativeByteBuffer *stream);
};
class TL_help_getCdnConfig : public TLObject {
public:
static const uint32_t constructor = 0x52029342;
bool isNeedLayer();
TLObject *deserializeResponse(NativeByteBuffer *stream, uint32_t constructor, bool &error);
void serializeToStream(NativeByteBuffer *stream);
};
class TL_disabledFeature : public TLObject {
public:
......@@ -70,7 +110,7 @@ public:
class TL_config : public TLObject {
public:
static const uint32_t constructor = 0xcb601684;
static const uint32_t constructor = 0x7feec888;
int32_t flags;
int32_t date;
......@@ -101,6 +141,8 @@ public:
int32_t call_connect_timeout_ms;
int32_t call_packet_timeout_ms;
std::string me_url_prefix;
std::string suggested_lang_code;
int32_t lang_pack_version;
std::vector<std::unique_ptr<TL_disabledFeature>> disabled_features;
static TL_config *TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error);
......@@ -271,6 +313,7 @@ public:
int32_t bot_info_version;
std::string restriction_reason;
std::string bot_inline_placeholder;
std::string lang_code;
static User *TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error);
};
......@@ -287,7 +330,7 @@ public:
class TL_user : public User {
public:
static const uint32_t constructor = 0xd10d979a;
static const uint32_t constructor = 0x2e13f4c3;
void readParams(NativeByteBuffer *stream, bool &error);
void serializeToStream(NativeByteBuffer *stream);
......
......@@ -20,6 +20,7 @@ public:
ByteStream();
~ByteStream();
void append(NativeByteBuffer *buffer);
void append(uint8_t *buffer, uint32_t size);
bool hasData();
void get(NativeByteBuffer *dst);
void discard(uint32_t count);
......
......@@ -45,7 +45,7 @@ void Connection::suspendConnection() {
DEBUG_D("connection(%p, dc%u, type %d) suspend", this, currentDatacenter->getDatacenterId(), connectionType);
connectionState = TcpConnectionStageSuspended;
dropConnection();
ConnectionsManager::getInstance().onConnectionClosed(this);
ConnectionsManager::getInstance().onConnectionClosed(this, 0);
firstPacketSent = false;
if (restOfTheData != nullptr) {
restOfTheData->reuse();
......@@ -216,33 +216,36 @@ void Connection::onReceivedData(NativeByteBuffer *buffer) {
void Connection::connect() {
if (!ConnectionsManager::getInstance().isNetworkAvailable()) {
ConnectionsManager::getInstance().onConnectionClosed(this);
ConnectionsManager::getInstance().onConnectionClosed(this, 0);
return;
}
if ((connectionState == TcpConnectionStageConnected || connectionState == TcpConnectionStageConnecting)) {
return;
}
connectionState = TcpConnectionStageConnecting;
bool ipv6 = ConnectionsManager::getInstance().isIpv6Enabled();
uint32_t ipv6 = ConnectionsManager::getInstance().isIpv6Enabled() ? TcpAddressFlagIpv6 : 0;
uint32_t isStatic = !ConnectionsManager::getInstance().proxyAddress.empty() ? TcpAddressFlagStatic : 0;
if (connectionType == ConnectionTypeDownload) {
currentAddressFlags = 2;
hostAddress = currentDatacenter->getCurrentAddress(currentAddressFlags | (ipv6 ? 1 : 0));
currentAddressFlags = TcpAddressFlagDownload | isStatic;
hostAddress = currentDatacenter->getCurrentAddress(currentAddressFlags | ipv6);
if (hostAddress.empty()) {
currentAddressFlags = 0;
hostAddress = currentDatacenter->getCurrentAddress(currentAddressFlags | (ipv6 ? 1 : 0));
currentAddressFlags = isStatic;
hostAddress = currentDatacenter->getCurrentAddress(currentAddressFlags | ipv6);
}
if (hostAddress.empty() && ipv6) {
currentAddressFlags = 2;
ipv6 = 0;
currentAddressFlags = TcpAddressFlagDownload | isStatic;
hostAddress = currentDatacenter->getCurrentAddress(currentAddressFlags);
if (hostAddress.empty()) {
currentAddressFlags = 0;
currentAddressFlags = isStatic;
hostAddress = currentDatacenter->getCurrentAddress(currentAddressFlags);
}
}
} else {
currentAddressFlags = 0;
hostAddress = currentDatacenter->getCurrentAddress(currentAddressFlags | (ipv6 ? 1 : 0));
if (ipv6 && hostAddress.empty()) {
currentAddressFlags = isStatic;
hostAddress = currentDatacenter->getCurrentAddress(currentAddressFlags | ipv6);
if (hostAddress.empty() && ipv6) {
ipv6 = 0;
hostAddress = currentDatacenter->getCurrentAddress(currentAddressFlags);
}
}
......@@ -259,7 +262,7 @@ void Connection::connect() {
lastPacketLength = 0;
wasConnected = false;
hasSomeDataSinceLastConnect = false;
openConnection(hostAddress, hostPort, ipv6, ConnectionsManager::getInstance().currentNetworkType);
openConnection(hostAddress, hostPort, ipv6 != 0, ConnectionsManager::getInstance().currentNetworkType);
if (connectionType == ConnectionTypePush) {
if (isTryingNextPort) {
setTimeout(20);
......@@ -273,7 +276,7 @@ void Connection::connect() {
if (connectionType == ConnectionTypeUpload) {
setTimeout(25);
} else {
setTimeout(15);
setTimeout(12);
}
}
}
......@@ -285,6 +288,14 @@ void Connection::reconnect() {
connect();
}
bool Connection::hasUsefullData() {
return usefullData;
}
void Connection::setHasUsefullData() {
usefullData = true;
}
void Connection::sendData(NativeByteBuffer *buff, bool reportAck) {
if (buff == nullptr) {
return;
......@@ -391,7 +402,8 @@ void Connection::onDisconnected(int reason) {
if (connectionState != TcpConnectionStageSuspended && connectionState != TcpConnectionStageIdle) {
connectionState = TcpConnectionStageIdle;
}
ConnectionsManager::getInstance().onConnectionClosed(this);
ConnectionsManager::getInstance().onConnectionClosed(this, reason);
usefullData = false;
uint32_t datacenterId = currentDatacenter->getDatacenterId();
if (connectionState == TcpConnectionStageIdle && connectionType == ConnectionTypeGeneric && (currentDatacenter->isHandshaking() || datacenterId == ConnectionsManager::getInstance().currentDatacenterId || datacenterId == ConnectionsManager::getInstance().movingToDatacenterId)) {
......
......@@ -31,6 +31,8 @@ public:
void connect();
void suspendConnection();
void sendData(NativeByteBuffer *buffer, bool reportAck);
bool hasUsefullData();
void setHasUsefullData();
uint32_t getConnectionToken();
ConnectionType getConnectionType();
Datacenter *getDatacenter();
......@@ -68,6 +70,7 @@ private:
bool wasConnected = false;
uint32_t willRetryConnectCount = 5;
Timer *reconnectTimer;
bool usefullData = false;
AES_KEY encryptKey;
uint8_t encryptIv[16];
......
......@@ -24,9 +24,11 @@ public:
ConnectionSocket();
virtual ~ConnectionSocket();
void writeBuffer(uint8_t *data, uint32_t size);
void writeBuffer(NativeByteBuffer *buffer);
void openConnection(std::string address, uint16_t port, bool ipv6, int32_t networkType);
void setTimeout(time_t timeout);
time_t getTimeout();
bool isDisconnected();
void dropConnection();
......@@ -43,11 +45,16 @@ private:
struct sockaddr_in socketAddress;
struct sockaddr_in6 socketAddress6;
int socketFd = -1;
time_t timeout = 15;
time_t timeout = 12;
bool onConnectedSent = false;
int64_t lastEventTime = 0;
EventObject *eventObject;
int32_t currentNetworkType;
bool isIpv6;
std::string currentAddress;
uint16_t currentPort;
uint8_t proxyAuthState;
bool checkSocketError();
void closeSocket(int reason);
......
......@@ -45,6 +45,7 @@ public:
int64_t getCurrentTimeMillis();
int64_t getCurrentTimeMonotonicMillis();
int32_t getCurrentTime();
bool isTestBackend();
int32_t getTimeDifference();
int32_t sendRequest(TLObject *object, onCompleteFunc onComplete, onQuickAckFunc onQuickAck, uint32_t flags, uint32_t datacenterId, ConnectionType connetionType, bool immediate);
void sendRequest(TLObject *object, onCompleteFunc onComplete, onQuickAckFunc onQuickAck, uint32_t flags, uint32_t datacenterId, ConnectionType connetionType, bool immediate, int32_t requestToken);
......@@ -61,14 +62,17 @@ public:
void pauseNetwork();
void setNetworkAvailable(bool value, int32_t type);
void setUseIpv6(bool value);
void init(uint32_t version, int32_t layer, int32_t apiId, std::string deviceModel, std::string systemVersion, std::string appVersion, std::string langCode, std::string configPath, std::string logPath, int32_t userId, bool isPaused, bool enablePushConnection, bool hasNetwork, int32_t networkType);
void updateDcSettings(uint32_t datacenterId);
void init(uint32_t version, int32_t layer, int32_t apiId, std::string deviceModel, std::string systemVersion, std::string appVersion, std::string langCode, std::string systemLangCode, std::string configPath, std::string logPath, int32_t userId, bool isPaused, bool enablePushConnection, bool hasNetwork, int32_t networkType);
void setProxySettings(std::string address, uint16_t port, std::string username, std::string password);
void setLangCode(std::string langCode);
void updateDcSettings(uint32_t datacenterId, bool workaround);
void setPushConnectionEnabled(bool value);
void applyDnsConfig(NativeByteBuffer *buffer);
void setMtProtoVersion(int version);
int32_t getMtProtoVersion();
#ifdef ANDROID
void sendRequest(TLObject *object, onCompleteFunc onComplete, onQuickAckFunc onQuickAck, uint32_t flags, uint32_t datacenterId, ConnectionType connetionType, bool immediate, int32_t requestToken, jobject ptr1, jobject ptr2);
void sendRequest(TLObject *object, onCompleteFunc onComplete, onQuickAckFunc onQuickAck, onWriteToSocketFunc onWriteToSocket, uint32_t flags, uint32_t datacenterId, ConnectionType connetionType, bool immediate, int32_t requestToken, jobject ptr1, jobject ptr2, jobject ptr3);
static void useJavaVM(JavaVM *vm, bool useJavaByteBuffers);
#endif
......@@ -78,6 +82,7 @@ private:
void initDatacenters();
void loadConfig();
void saveConfig();
void saveConfigInternal(NativeByteBuffer *buffer);
void select();
void wakeup();
void processServerResponse(TLObject *message, int64_t messageId, int32_t messageSeqNo, int64_t messageSalt, Connection *connection, int64_t innerMsgId, int64_t containerMessageId);
......@@ -102,7 +107,7 @@ private:
void scheduleTask(std::function<void()> task);
void scheduleEvent(EventObject *eventObject, uint32_t time);
void removeEvent(EventObject *eventObject);
void onConnectionClosed(Connection *connection);
void onConnectionClosed(Connection *connection, int reason);
void onConnectionConnected(Connection *connection);
void onConnectionQuickAckReceived(Connection *connection, int32_t ack);
void onConnectionDataReceived(Connection *connection, NativeByteBuffer *data, uint32_t length);
......@@ -134,6 +139,9 @@ private:
int64_t lastPushPingTime = 0;
bool sendingPushPing = false;
bool updatingDcSettings = false;
bool updatingDcSettingsWorkaround = false;
int32_t disconnectTimeoutAmount = 0;
int32_t requestingSecondAddress = 0;
int32_t updatingDcStartTime = 0;
int32_t lastDcUpdateTime = 0;
int64_t lastPingTime = getCurrentTimeMonotonicMillis();
......@@ -147,6 +155,11 @@ private:
std::map<int32_t, std::vector<int32_t>> requestsByGuids;
std::map<int32_t, int32_t> guidsByRequests;
std::string proxyUser = "";
std::string proxyPassword = "";
std::string proxyAddress = "";
std::uint16_t proxyPort = 1080;
pthread_t networkThread;
pthread_mutex_t mutex;
std::queue<std::function<void()>> pendingTasks;
......@@ -176,6 +189,7 @@ private:
std::string currentSystemVersion;
std::string currentAppVersion;
std::string currentLangCode;
std::string currentSystemLangCode;
std::string currentConfigPath;
std::string currentLogPath;
int32_t currentUserId = 0;
......
This diff is collapsed.
......@@ -19,6 +19,7 @@ class TL_future_salt;
class Connection;
class NativeByteBuffer;
class TL_future_salt;
class TL_help_configSimple;
class ByteArray;
class TLObject;
class Config;
......@@ -35,7 +36,7 @@ public:
void addAddressAndPort(std::string address, uint32_t port, uint32_t flags);
void nextAddressOrPort(uint32_t flags);
void storeCurrentAddressAndPortNum();
void replaceAddressesAndPorts(std::vector<std::string> &newAddresses, std::map<std::string, uint32_t> &newPorts, uint32_t flags);
void replaceAddresses(std::vector<TcpAddress> &newAddresses, uint32_t flags);
void serializeToStream(NativeByteBuffer *stream);
void clear();
void clearServerSalts();
......@@ -55,6 +56,7 @@ public:
Connection *getUploadConnection(uint8_t num, bool create);
Connection *getGenericConnection(bool create);
Connection *getPushConnection(bool create);
Connection *getTempConnection(bool create);
Connection *getConnectionByType(uint32_t connectionType, bool create);
static void aesIgeEncryption(uint8_t *buffer, uint8_t *key, uint8_t *iv, bool encrypt, bool changeIv, uint32_t length);
......@@ -72,21 +74,24 @@ private:
uint32_t datacenterId;
Connection *genericConnection = nullptr;
Connection *downloadConnections[DOWNLOAD_CONNECTIONS_COUNT];
Connection *tempConnection = nullptr;
Connection *downloadConnection[DOWNLOAD_CONNECTIONS_COUNT];
Connection *uploadConnection[UPLOAD_CONNECTIONS_COUNT];
Connection *pushConnection = nullptr;
uint32_t lastInitVersion = 0;
bool authorized = false;
std::vector<std::string> addressesIpv4;
std::vector<std::string> addressesIpv6;
std::vector<std::string> addressesIpv4Download;
std::vector<std::string> addressesIpv6Download;
std::map<std::string, uint32_t> ports;
std::vector<TcpAddress> addressesIpv4;
std::vector<TcpAddress> addressesIpv6;
std::vector<TcpAddress> addressesIpv4Download;
std::vector<TcpAddress> addressesIpv6Download;
std::vector<TcpAddress> addressesIpv4Temp;
std::vector<std::unique_ptr<TL_future_salt>> serverSalts;
uint32_t currentPortNumIpv4 = 0;
uint32_t currentAddressNumIpv4 = 0;
uint32_t currentPortNumIpv4Temp = 0;
uint32_t currentAddressNumIpv4Temp = 0;
uint32_t currentPortNumIpv6 = 0;
uint32_t currentAddressNumIpv6 = 0;
uint32_t currentPortNumIpv4Download = 0;
......@@ -97,13 +102,15 @@ private:
int64_t authKeyId = 0;
int32_t overridePort = -1;
Config *config = nullptr;
bool isCdnDatacenter = false;
const uint32_t configVersion = 5;
const uint32_t configVersion = 7;
const uint32_t paramsConfigVersion = 1;
Connection *createDownloadConnection(uint8_t num);
Connection *createUploadConnection(uint8_t num);
Connection *createGenericConnection();
Connection *createTempConnection();
Connection *createPushConnection();
Connection *createConnectionByType(uint32_t connectionType);
......@@ -120,11 +127,16 @@ private:
void sendRequestData(TLObject *object, bool important);
void cleanupHandshake();
void sendAckRequest(int64_t messageId);
int32_t selectPublicKey(std::vector<int64_t> &fingerprints);
bool exportingAuthorization = false;
void exportAuthorization();
static void saveCdnConfig();
static void saveCdnConfigInternal(NativeByteBuffer *buffer);
static void loadCdnConfig(Datacenter *datacenter);
static TL_help_configSimple *decodeSimpleConfig(NativeByteBuffer *buffer);
friend class ConnectionsManager;
};
......
......@@ -21,7 +21,7 @@
#define DEFAULT_DATACENTER_ID INT_MAX
#define DC_UPDATE_TIME 60 * 60
#define DOWNLOAD_CONNECTIONS_COUNT 2
#define UPLOAD_CONNECTIONS_COUNT 2
#define UPLOAD_CONNECTIONS_COUNT 4
#define CONNECTION_BACKGROUND_KEEP_TIME 10000
#define DOWNLOAD_CHUNK_SIZE 1024 * 32
......@@ -44,6 +44,7 @@ class FileLoadOperation;
typedef std::function<void(TLObject *response, TL_error *error, int32_t networkType)> onCompleteFunc;
typedef std::function<void()> onQuickAckFunc;
typedef std::function<void()> onWriteToSocketFunc;
typedef std::list<std::unique_ptr<Request>> requestsList;
typedef requestsList::iterator requestsIter;
......@@ -59,12 +60,23 @@ enum ConnectionType {
ConnectionTypeDownload = 2,
ConnectionTypeUpload = 4,
ConnectionTypePush = 8,
ConnectionTypeTemp = 16
};
enum TcpAddressFlag {
TcpAddressFlagIpv6 = 1,
TcpAddressFlagDownload = 2,
TcpAddressFlagO = 4,
TcpAddressFlagCdn = 8,
TcpAddressFlagStatic = 16,
TcpAddressFlagTemp = 2048
};
enum ConnectionState {
ConnectionStateConnecting = 1,
ConnectionStateWaitingForNetwork = 2,
ConnectionStateConnected = 3
ConnectionStateConnected = 3,
ConnectionStateConnectingViaProxy = 4
};
enum EventObjectType {
......@@ -87,6 +99,20 @@ enum FileLoadFailReason {
FileLoadFailReasonRetryLimit
};
class TcpAddress {
public:
std::string address;
int32_t flags;
int32_t port;
TcpAddress(std::string addr, int32_t p, int32_t f) {
address = addr;
port = p;
flags = f;
}
};
typedef std::function<void(std::string path)> onFinishedFunc;
typedef std::function<void(FileLoadFailReason reason)> onFailedFunc;
typedef std::function<void(float progress)> onProgressChangedFunc;
......@@ -101,6 +127,7 @@ typedef struct ConnectiosManagerDelegate {
virtual void onInternalPushReceived() = 0;
virtual void onBytesSent(int32_t amount, int32_t networkType) = 0;
virtual void onBytesReceived(int32_t amount, int32_t networkType) = 0;
virtual void onRequestNewServerIpAndPort(int32_t second) = 0;
} ConnectiosManagerDelegate;
#define AllConnectionTypes ConnectionTypeGeneric | ConnectionTypeDownload | ConnectionTypeUpload
......
......@@ -7,6 +7,7 @@
*/
#include <memory.h>
#include <arpa/inet.h>
#include "MTProtoScheme.h"
#include "ApiScheme.h"
#include "FileLog.h"
......@@ -852,6 +853,47 @@ void initConnection::serializeToStream(NativeByteBuffer *stream) {
stream->writeString(device_model);
stream->writeString(system_version);
stream->writeString(app_version);
stream->writeString(system_lang_code);
stream->writeString(lang_pack);
stream->writeString(lang_code);
query->serializeToStream(stream);
}
void TL_ipPort::readParams(NativeByteBuffer *stream, bool &error) {
struct in_addr ip_addr;
ip_addr.s_addr = htonl(stream->readUint32(&error));
ipv4 = inet_ntoa(ip_addr);
port = stream->readUint32(&error);
}
TL_help_configSimple *TL_help_configSimple::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error) {
if (TL_help_configSimple::constructor != constructor) {
error = true;
DEBUG_E("can't parse magic %x in TL_help_configSimple", constructor);
return nullptr;
}
TL_help_configSimple *result = new TL_help_configSimple();
result->readParams(stream, error);
return result;
}
void TL_help_configSimple::readParams(NativeByteBuffer *stream, bool &error) {
date = stream->readInt32(&error);
expires = stream->readInt32(&error);
dc_id = stream->readUint32(&error);
int32_t magic = stream->readInt32(&error);
if (magic != 0x1cb5c415) {
error = true;
DEBUG_E("wrong Vector magic, got %x", magic);
return;
}
uint32_t count = stream->readUint32(&error);
for (uint32_t a = 0; a < count; a++) {
TL_ipPort *object = new TL_ipPort();
object->readParams(stream, error);
if (error) {
return;
}
ip_port_list.push_back(std::unique_ptr<TL_ipPort>(object));
}
}
......@@ -614,16 +614,41 @@ public:
class initConnection : public TLObject {
public:
static const uint32_t constructor = 0x69796de9;
static const uint32_t constructor = 0xc7481da6;
int32_t api_id;
std::string device_model;
std::string system_version;
std::string app_version;
std::string system_lang_code;
std::string lang_pack;
std::string lang_code;
std::unique_ptr<TLObject> query;
void serializeToStream(NativeByteBuffer *stream);
};
class TL_ipPort : public TLObject {
public:
std::string ipv4;
uint32_t port;
void readParams(NativeByteBuffer *stream, bool &error);
};
class TL_help_configSimple : public TLObject {
public:
static const uint32_t constructor = 0xd997c3c5;
int32_t date;
int32_t expires;
uint32_t dc_id;
std::vector<std::unique_ptr<TL_ipPort>> ip_port_list;
static TL_help_configSimple *TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error);
void readParams(NativeByteBuffer *stream, bool &error);
};
#endif
......@@ -12,13 +12,14 @@
#include "MTProtoScheme.h"
#include "ConnectionsManager.h"
Request::Request(int32_t token, ConnectionType type, uint32_t flags, uint32_t datacenter, onCompleteFunc completeFunc, onQuickAckFunc quickAckFunc) {
Request::Request(int32_t token, ConnectionType type, uint32_t flags, uint32_t datacenter, onCompleteFunc completeFunc, onQuickAckFunc quickAckFunc, onWriteToSocketFunc writeToSocketFunc) {
requestToken = token;
connectionType = type;
requestFlags = flags;
datacenterId = datacenter;
onCompleteRequestCallback = completeFunc;
onQuickAckCallback = quickAckFunc;
onWriteToSocketCallback = writeToSocketFunc;
dataType = (uint8_t) (requestFlags >> 24);
}
......@@ -32,6 +33,10 @@ Request::~Request() {
jniEnv->DeleteGlobalRef(ptr2);
ptr2 = nullptr;
}
if (ptr3 != nullptr) {
jniEnv->DeleteGlobalRef(ptr3);
ptr3 = nullptr;
}
#endif
}
......@@ -59,6 +64,12 @@ void Request::onComplete(TLObject *result, TL_error *error, int32_t networkType)
}
}
void Request::onWriteToSocket() {
if (onWriteToSocketCallback != nullptr) {
onWriteToSocketCallback();
}
}
void Request::onQuickAck() {
if (onQuickAckCallback != nullptr) {
onQuickAckCallback();
......
......@@ -24,7 +24,7 @@ class TL_error;
class Request {
public:
Request(int32_t token, ConnectionType type, uint32_t flags, uint32_t datacenter, onCompleteFunc completeFunc, onQuickAckFunc quickAckFunc);
Request(int32_t token, ConnectionType type, uint32_t flags, uint32_t datacenter, onCompleteFunc completeFunc, onQuickAckFunc quickAckFunc, onWriteToSocketFunc writeToSocketFunc);
~Request();
int64_t messageId = 0;
......@@ -50,17 +50,20 @@ public:
std::unique_ptr<TLObject> rpcRequest;
onCompleteFunc onCompleteRequestCallback;
onQuickAckFunc onQuickAckCallback;
onWriteToSocketFunc onWriteToSocketCallback;
void addRespondMessageId(int64_t id);
bool respondsToMessageId(int64_t id);
void clear(bool time);
void onComplete(TLObject *result, TL_error *error, int32_t networkType);
void onQuickAck();
void onWriteToSocket();
TLObject *getRpcRequest();
#ifdef ANDROID
jobject ptr1 = nullptr;
jobject ptr2 = nullptr;
jobject ptr3 = nullptr;
#endif
private:
......
......@@ -66,6 +66,7 @@
android:allowBackup="false"
android:hardwareAccelerated="@bool/useHardwareAcceleration"
android:icon="@drawable/ic_launcher"
android:roundIcon="@drawable/ic_launcher"
android:largeHeap="true"
android:theme="@style/Theme.TMessages.Start"
android:manageSpaceActivity="org.telegram.ui.ManageSpaceActivity">
......@@ -124,6 +125,8 @@
<data android:host="telegram.me" android:scheme="https" />
<data android:host="telegram.dog" android:scheme="http" />
<data android:host="telegram.dog" android:scheme="https" />
<data android:host="telesco.pe" android:scheme="http" />
<data android:host="telesco.pe" android:scheme="https" />
<data android:host="t.me" android:scheme="http" />
<data android:host="t.me" android:scheme="https" />
</intent-filter>
......@@ -176,6 +179,15 @@
android:resizeableActivity="false"
android:windowSoftInputMode="adjustResize|stateHidden">
</activity>
<activity
android:name=".GoogleVoiceClientActivity"
android:exported="true">
<intent-filter>
<action android:name="com.google.android.voicesearch.SEND_MESSAGE_TO_CONTACTS" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
</activity>
<activity
android:name="org.telegram.ui.VoIPActivity"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
......@@ -254,12 +266,23 @@
<service android:name=".ClearCacheService" android:exported="false"/>
<service android:name=".VideoEncodingService" android:enabled="true"/>
<service android:name=".voip.VoIPService" android:enabled="true"/>
<service android:name=".GoogleVoiceClientService"/>
<service android:name=".MusicPlayerService" android:exported="true" android:enabled="true"/>
<service android:name=".MusicBrowserService" android:exported="true">
<intent-filter>
<action android:name="android.media.browse.MediaBrowserService"/>
</intent-filter>
</service>
<service android:name=".WearDataLayerListenerService">
<intent-filter>
<!-- listeners receive events that match the action and data filters -->
<action android:name="com.google.android.gms.wearable.DATA_CHANGED" />
<action android:name="com.google.android.gms.wearable.MESSAGE_RECEIVED" />
<action android:name="com.google.android.gms.wearable.CAPABILITY_CHANGED" />
<action android:name="com.google.android.gms.wearable.CHANNEL_EVENT" />
<data android:scheme="wear" android:host="*" />
</intent-filter>
</service>
<receiver android:name=".MusicPlayerReceiver" >
<intent-filter>
......@@ -315,7 +338,11 @@
<meta-data android:name="com.google.android.gms.car.notification.SmallIcon" android:resource="@drawable/ic_player" />
<meta-data android:name="com.google.android.gms.car.application" android:resource="@xml/automotive_app_desc" />
<meta-data android:name="com.google.android.gms.vision.DEPENDENCIES" android:value="face" />
<meta-data android:name="com.google.android.gms.vision.DEPENDENCIES" android:value="face" />
<meta-data android:name="com.samsung.android.icon_container.has_icon_container" android:value="true"/>
<meta-data android:name="android.max_aspect" android:value="2.5" />
</application>
</manifest>
......@@ -18,6 +18,7 @@ import android.content.ContentUris;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
......@@ -111,6 +112,7 @@ public class AndroidUtilities {
public static int statusBarHeight = 0;
public static float density = 1;
public static Point displaySize = new Point();
public static int roundMessageSize;
public static boolean incorrectDisplaySizeFix;
public static Integer photoSize = null;
public static DisplayMetrics displayMetrics = new DisplayMetrics();
......@@ -549,6 +551,13 @@ public class AndroidUtilities {
displaySize.y = newSize;
}
}
if (roundMessageSize == 0) {
if (AndroidUtilities.isTablet()) {
roundMessageSize = (int) (AndroidUtilities.getMinTabletSide() * 0.6f);
} else {
roundMessageSize = (int) (Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) * 0.6f);
}
}
FileLog.e("display size = " + displaySize.x + " " + displaySize.y + " " + displayMetrics.xdpi + "x" + displayMetrics.ydpi);
} catch (Exception e) {
FileLog.e(e);
......@@ -1606,6 +1615,10 @@ public class AndroidUtilities {
}
}
public static boolean isBannedForever(int time) {
return Math.abs(time - System.currentTimeMillis() / 1000) > 5 * 365 * 24 * 60 * 60;
}
public static void setRectToRect(Matrix matrix, RectF src, RectF dst, int rotation, Matrix.ScaleToFit align) {
float tx, sx;
float ty, sy;
......@@ -1641,4 +1654,104 @@ public class AndroidUtilities {
matrix.preScale(sx, sy);
matrix.preTranslate(tx, ty);
}
public static boolean handleProxyIntent(Activity activity, Intent intent) {
if (intent == null) {
return false;
}
try {
if ((intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) != 0) {
return false;
}
Uri data = intent.getData();
if (data != null) {
String user = null;
String password = null;
String port = null;
String address = null;
String scheme = data.getScheme();
if (scheme != null) {
if ((scheme.equals("http") || scheme.equals("https"))) {
String host = data.getHost().toLowerCase();
if (host.equals("telegram.me") || host.equals("t.me") || host.equals("telegram.dog") || host.equals("telesco.pe")) {
String path = data.getPath();
if (path != null) {
if (path.startsWith("/socks")) {
address = data.getQueryParameter("server");
port = data.getQueryParameter("port");
user = data.getQueryParameter("user");
password = data.getQueryParameter("pass");
}
}
}
} else if (scheme.equals("tg")) {
String url = data.toString();
if (url.startsWith("tg:socks") || url.startsWith("tg://socks")) {
url = url.replace("tg:proxy", "tg://telegram.org").replace("tg://proxy", "tg://telegram.org");
data = Uri.parse(url);
address = data.getQueryParameter("server");
port = data.getQueryParameter("port");
user = data.getQueryParameter("user");
password = data.getQueryParameter("pass");
}
}
}
if (!TextUtils.isEmpty(address) && !TextUtils.isEmpty(port)) {
if (user == null) {
user = "";
}
if (password == null) {
password = "";
}
showProxyAlert(activity, address, port, user, password);
return true;
}
}
} catch (Exception ignore) {
}
return false;
}
public static void showProxyAlert(Activity activity, final String address, final String port, final String user, final String password) {
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setTitle(LocaleController.getString("Proxy", R.string.Proxy));
StringBuilder stringBuilder = new StringBuilder(LocaleController.getString("EnableProxyAlert", R.string.EnableProxyAlert));
stringBuilder.append("\n\n");
stringBuilder.append(LocaleController.getString("UseProxyAddress", R.string.UseProxyAddress)).append(": ").append(address).append("\n");
stringBuilder.append(LocaleController.getString("UseProxyPort", R.string.UseProxyPort)).append(": ").append(port).append("\n");
if (!TextUtils.isEmpty(user)) {
stringBuilder.append(LocaleController.getString("UseProxyUsername", R.string.UseProxyUsername)).append(": ").append(user).append("\n");
}
if (!TextUtils.isEmpty(password)) {
stringBuilder.append(LocaleController.getString("UseProxyPassword", R.string.UseProxyPassword)).append(": ").append(password).append("\n");
}
stringBuilder.append("\n").append(LocaleController.getString("EnableProxyAlert2", R.string.EnableProxyAlert2));
builder.setMessage(stringBuilder.toString());
builder.setPositiveButton(LocaleController.getString("ConnectingToProxyEnable", R.string.ConnectingToProxyEnable), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
SharedPreferences.Editor editor = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE).edit();
editor.putBoolean("proxy_enabled", true);
editor.putString("proxy_ip", address);
int p = Utilities.parseInt(port);
editor.putInt("proxy_port", p);
if (TextUtils.isEmpty(password)) {
editor.remove("proxy_pass");
} else {
editor.putString("proxy_pass", password);
}
if (TextUtils.isEmpty(user)) {
editor.remove("proxy_user");
} else {
editor.putString("proxy_user", user);
}
editor.commit();
ConnectionsManager.native_setProxySettings(address, p, user, password);
NotificationCenter.getInstance().postNotificationName(NotificationCenter.proxySettingsChanged);
}
});
builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null);
builder.show().setCanceledOnTouchOutside(true);
}
}
......@@ -143,24 +143,27 @@ public class ApplicationLoader extends Application {
UserConfig.loadConfig();
String deviceModel;
String systemLangCode;
String langCode;
String appVersion;
String systemVersion;
String configPath = getFilesDirFixed().toString();
try {
systemLangCode = LocaleController.getSystemLocaleStringIso639();
langCode = LocaleController.getLocaleStringIso639();
deviceModel = Build.MANUFACTURER + Build.MODEL;
PackageInfo pInfo = ApplicationLoader.applicationContext.getPackageManager().getPackageInfo(ApplicationLoader.applicationContext.getPackageName(), 0);
appVersion = pInfo.versionName + " (" + pInfo.versionCode + ")";
systemVersion = "SDK " + Build.VERSION.SDK_INT;
} catch (Exception e) {
langCode = "en";
systemLangCode = "en";
langCode = "";
deviceModel = "Android unknown";
appVersion = "App version unknown";
systemVersion = "SDK " + Build.VERSION.SDK_INT;
}
if (langCode.trim().length() == 0) {
if (systemLangCode.trim().length() == 0) {
langCode = "en";
}
if (deviceModel.trim().length() == 0) {
......@@ -177,7 +180,7 @@ public class ApplicationLoader extends Application {
boolean enablePushConnection = preferences.getBoolean("pushConnection", true);
MessagesController.getInstance();
ConnectionsManager.getInstance().init(BuildVars.BUILD_VERSION, TLRPC.LAYER, BuildVars.APP_ID, deviceModel, systemVersion, appVersion, langCode, configPath, FileLog.getNetworkLogPath(), UserConfig.getClientUserId(), enablePushConnection);
ConnectionsManager.getInstance().init(BuildVars.BUILD_VERSION, TLRPC.LAYER, BuildVars.APP_ID, deviceModel, systemVersion, appVersion, langCode, systemLangCode, configPath, FileLog.getNetworkLogPath(), UserConfig.getClientUserId(), enablePushConnection);
if (UserConfig.getCurrentUser() != null) {
MessagesController.getInstance().putUser(UserConfig.getCurrentUser(), true);
ConnectionsManager.getInstance().applyCountryPortNumber(UserConfig.getCurrentUser().phone);
......
......@@ -180,7 +180,7 @@ public class Bitmaps {
if (config != null) {
switch (config) {
case RGB_565:
newConfig = Bitmap.Config.RGB_565;
newConfig = Bitmap.Config.ARGB_8888;
break;
case ALPHA_8:
newConfig = Bitmap.Config.ALPHA_8;
......
......@@ -11,8 +11,8 @@ package org.telegram.messenger;
public class BuildVars {
public static boolean DEBUG_VERSION = false;
public static boolean DEBUG_PRIVATE_VERSION = false;
public static int BUILD_VERSION = 957;
public static String BUILD_VERSION_STRING = "3.18";
public static int BUILD_VERSION = 1030;
public static String BUILD_VERSION_STRING = "4.1";
public static int APP_ID = 0; //obtain your own APP_ID at https://core.telegram.org/api/obtaining_api_id
public static String APP_HASH = ""; //obtain your own APP_HASH at https://core.telegram.org/api/obtaining_api_id
public static String HOCKEY_APP_HASH = "your-hockeyapp-api-key-here";
......
......@@ -23,7 +23,7 @@ public class ChatObject {
}
public static boolean isKickedFromChat(TLRPC.Chat chat) {
return chat == null || chat instanceof TLRPC.TL_chatEmpty || chat instanceof TLRPC.TL_chatForbidden || chat instanceof TLRPC.TL_channelForbidden || chat.kicked || chat.deactivated;
return chat == null || chat instanceof TLRPC.TL_chatEmpty || chat instanceof TLRPC.TL_chatForbidden || chat instanceof TLRPC.TL_channelForbidden || chat.kicked || chat.deactivated || chat.banned_rights != null && chat.banned_rights.view_messages;
}
public static boolean isNotInChat(TLRPC.Chat chat) {
......@@ -34,6 +34,50 @@ public class ChatObject {
return chat instanceof TLRPC.TL_channel || chat instanceof TLRPC.TL_channelForbidden;
}
public static boolean hasAdminRights(TLRPC.Chat chat) {
return chat != null && (chat.creator || chat.admin_rights != null && chat.admin_rights.flags != 0);
}
public static boolean canChangeChatInfo(TLRPC.Chat chat) {
return chat != null && (chat.creator || chat.admin_rights != null && chat.admin_rights.change_info);
}
public static boolean canAddAdmins(TLRPC.Chat chat) {
return chat != null && (chat.creator || chat.admin_rights != null && chat.admin_rights.add_admins);
}
public static boolean canBlockUsers(TLRPC.Chat chat) {
return chat != null && (chat.creator || chat.admin_rights != null && chat.admin_rights.ban_users);
}
public static boolean canSendStickers(TLRPC.Chat chat) {
return chat == null || chat != null && (chat.banned_rights == null || !chat.banned_rights.send_media && !chat.banned_rights.send_stickers);
}
public static boolean canSendEmbed(TLRPC.Chat chat) {
return chat == null || chat != null && (chat.banned_rights == null || !chat.banned_rights.send_media && !chat.banned_rights.embed_links);
}
public static boolean canSendMessages(TLRPC.Chat chat) {
return chat == null || chat != null && (chat.banned_rights == null || !chat.banned_rights.send_messages);
}
public static boolean canPost(TLRPC.Chat chat) {
return chat != null && (chat.creator || chat.admin_rights != null && chat.admin_rights.post_messages);
}
public static boolean canAddViaLink(TLRPC.Chat chat) {
return chat != null && (chat.creator || chat.admin_rights != null && chat.admin_rights.invite_link);
}
public static boolean canAddUsers(TLRPC.Chat chat) {
return chat != null && (chat.creator || chat.admin_rights != null && chat.admin_rights.invite_users);
}
public static boolean canEditInfo(TLRPC.Chat chat) {
return chat != null && (chat.creator || chat.admin_rights != null && chat.admin_rights.change_info);
}
public static boolean isChannel(int chatId) {
TLRPC.Chat chat = MessagesController.getInstance().getChat(chatId);
return chat instanceof TLRPC.TL_channel || chat instanceof TLRPC.TL_channelForbidden;
......@@ -41,11 +85,11 @@ public class ChatObject {
public static boolean isCanWriteToChannel(int chatId) {
TLRPC.Chat chat = MessagesController.getInstance().getChat(chatId);
return chat != null && (chat.creator || chat.editor || chat.megagroup);
return chat != null && (chat.creator || chat.admin_rights != null && chat.admin_rights.post_messages || chat.megagroup);
}
public static boolean canWriteToChat(TLRPC.Chat chat) {
return !isChannel(chat) || chat.creator || chat.editor || !chat.broadcast;
return !isChannel(chat) || chat.creator || chat.admin_rights != null && chat.admin_rights.post_messages || !chat.broadcast;
}
public static TLRPC.Chat getChatByDialog(long did) {
......
......@@ -38,7 +38,15 @@ public class ClearCacheService extends IntentService {
@Override
public void run() {
long currentTime = System.currentTimeMillis();
long diff = 60 * 60 * 1000 * 24 * (keepMedia == 0 ? 7 : 30);
int days;
if (keepMedia == 0) {
days = 7;
} else if (keepMedia == 1) {
days = 30;
} else {
days = 3;
}
long diff = 60 * 60 * 1000 * 24 * days;
final HashMap<Integer, File> paths = ImageLoader.getInstance().createMediaPaths();
for (HashMap.Entry<Integer, File> entry : paths.entrySet()) {
if (entry.getKey() == FileLoader.MEDIA_DIR_CACHE) {
......
......@@ -24,7 +24,7 @@ public class DispatchQueue extends Thread {
start();
}
private void sendMessage(Message msg, int delay) {
public void sendMessage(Message msg, int delay) {
try {
syncLatch.await();
if (delay <= 0) {
......@@ -72,10 +72,19 @@ public class DispatchQueue extends Thread {
}
}
public void handleMessage(Message inputMessage) {
}
@Override
public void run() {
Looper.prepare();
handler = new Handler();
handler = new Handler() {
@Override
public void handleMessage(Message msg) {
DispatchQueue.this.handleMessage(msg);
}
};
syncLatch.countDown();
Looper.loop();
}
......
......@@ -16,6 +16,7 @@ import org.telegram.tgnet.NativeByteBuffer;
import org.telegram.tgnet.RequestDelegate;
import org.telegram.tgnet.TLObject;
import org.telegram.tgnet.TLRPC;
import org.telegram.tgnet.WriteToSocketDelegate;
import java.io.File;
import java.io.FileInputStream;
......@@ -34,8 +35,12 @@ public class FileUploadOperation {
}
private boolean isLastPart = false;
private final int maxRequestsCount = 8;
private int uploadChunkSize = 1024 * 128;
private static final int minUploadChunkSize = 64;
private static final int initialRequestsCount = 8;
private static final int maxUploadingKBytes = 1024 * 2;
private int maxRequestsCount;
private int currentUploadingBytes;
private int uploadChunkSize = 64 * 1024;
private ArrayList<byte[]> freeRequestIvs;
private int requestNum;
private String uploadingFilePath;
......@@ -98,7 +103,7 @@ public class FileUploadOperation {
@Override
public void run() {
preferences = ApplicationLoader.applicationContext.getSharedPreferences("uploadinfo", Activity.MODE_PRIVATE);
for (int a = 0; a < maxRequestsCount; a++) {
for (int a = 0; a < initialRequestsCount; a++) {
startUploadRequest();
}
}
......@@ -110,9 +115,14 @@ public class FileUploadOperation {
return;
}
state = 2;
for (Integer num : requestTokens.values()) {
ConnectionsManager.getInstance().cancelRequest(num, true);
}
Utilities.stageQueue.postRunnable(new Runnable() {
@Override
public void run() {
for (Integer num : requestTokens.values()) {
ConnectionsManager.getInstance().cancelRequest(num, true);
}
}
});
delegate.didFailedUploadingFile(this);
cleanup();
}
......@@ -183,12 +193,6 @@ public class FileUploadOperation {
try {
started = true;
if (stream == null) {
if (isEncrypted) {
freeRequestIvs = new ArrayList<>(maxRequestsCount);
for (int a = 0; a < maxRequestsCount; a++) {
freeRequestIvs.add(new byte[32]);
}
}
File cacheFile = new File(uploadingFilePath);
stream = new FileInputStream(cacheFile);
if (estimatedSize != 0) {
......@@ -206,7 +210,7 @@ public class FileUploadOperation {
}
}
uploadChunkSize = (int) Math.max(128, (totalFileSize + 1024 * 3000 - 1) / (1024 * 3000));
uploadChunkSize = (int) Math.max(minUploadChunkSize, (totalFileSize + 1024 * 3000 - 1) / (1024 * 3000));
if (1024 % uploadChunkSize != 0) {
int chunkSize = 64;
while (uploadChunkSize > chunkSize) {
......@@ -214,6 +218,14 @@ public class FileUploadOperation {
}
uploadChunkSize = chunkSize;
}
maxRequestsCount = maxUploadingKBytes / uploadChunkSize;
if (isEncrypted) {
freeRequestIvs = new ArrayList<>(maxRequestsCount);
for (int a = 0; a < maxRequestsCount; a++) {
freeRequestIvs.add(new byte[32]);
}
}
uploadChunkSize *= 1024;
totalPartsCount = (int) (totalFileSize + uploadChunkSize - 1) / uploadChunkSize;
......@@ -401,6 +413,9 @@ public class FileUploadOperation {
final long currentRequestBytesOffset = readBytesCount;
final int currentRequestPartNum = currentPartNum++;
final int requestSize = finalRequest.getObjectSize() + 4;
int connectionType = ConnectionsManager.ConnectionTypeUpload | ((requestNumFinal % 4) << 16);
int requestToken = ConnectionsManager.getInstance().sendRequest(finalRequest, new RequestDelegate() {
@Override
public void run(TLObject response, TLRPC.TL_error error) {
......@@ -451,6 +466,15 @@ public class FileUploadOperation {
delegate.didFinishUploadingFile(FileUploadOperation.this, null, result, key, iv);
cleanup();
}
if (currentType == ConnectionsManager.FileTypeAudio) {
StatsController.getInstance().incrementSentItemsCount(ConnectionsManager.getCurrentNetworkType(), StatsController.TYPE_AUDIOS, 1);
} else if (currentType == ConnectionsManager.FileTypeVideo) {
StatsController.getInstance().incrementSentItemsCount(ConnectionsManager.getCurrentNetworkType(), StatsController.TYPE_VIDEOS, 1);
} else if (currentType == ConnectionsManager.FileTypePhoto) {
StatsController.getInstance().incrementSentItemsCount(ConnectionsManager.getCurrentNetworkType(), StatsController.TYPE_PHOTOS, 1);
} else if (currentType == ConnectionsManager.FileTypeFile) {
StatsController.getInstance().incrementSentItemsCount(ConnectionsManager.getCurrentNetworkType(), StatsController.TYPE_FILES, 1);
}
} else if (currentUploadRequetsCount < maxRequestsCount) {
if (estimatedSize == 0) {
if (saveInfoTimes >= 4) {
......@@ -486,25 +510,27 @@ public class FileUploadOperation {
}
saveInfoTimes++;
}
startUploadRequest();
}
if (currentType == ConnectionsManager.FileTypeAudio) {
StatsController.getInstance().incrementSentItemsCount(ConnectionsManager.getCurrentNetworkType(), StatsController.TYPE_AUDIOS, 1);
} else if (currentType == ConnectionsManager.FileTypeVideo) {
StatsController.getInstance().incrementSentItemsCount(ConnectionsManager.getCurrentNetworkType(), StatsController.TYPE_VIDEOS, 1);
} else if (currentType == ConnectionsManager.FileTypePhoto) {
StatsController.getInstance().incrementSentItemsCount(ConnectionsManager.getCurrentNetworkType(), StatsController.TYPE_PHOTOS, 1);
} else if (currentType == ConnectionsManager.FileTypeFile) {
StatsController.getInstance().incrementSentItemsCount(ConnectionsManager.getCurrentNetworkType(), StatsController.TYPE_FILES, 1);
}
} else {
delegate.didFailedUploadingFile(FileUploadOperation.this);
cleanup();
}
}
}, 0, currentUploadRequetsCount % 2 == 0 ? ConnectionsManager.ConnectionTypeUpload : ConnectionsManager.ConnectionTypeUpload2);
}, null, new WriteToSocketDelegate() {
@Override
public void run() {
Utilities.stageQueue.postRunnable(new Runnable() {
@Override
public void run() {
if (currentUploadRequetsCount < maxRequestsCount) {
startUploadRequest();
}
}
});
}
}, 0, ConnectionsManager.DEFAULT_DATACENTER_ID, connectionType, true);
requestTokens.put(requestNumFinal, requestToken);
}
}
......@@ -11,12 +11,16 @@ package org.telegram.messenger;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Build;
import android.os.Bundle;
import com.google.android.gms.gcm.GcmListenerService;
import org.json.JSONObject;
import org.telegram.tgnet.ConnectionsManager;
import org.telegram.tgnet.TLRPC;
import static android.support.v4.net.ConnectivityManagerCompat.RESTRICT_BACKGROUND_STATUS_ENABLED;
public class GcmPushListenerService extends GcmListenerService {
......@@ -44,13 +48,52 @@ public class GcmPushListenerService extends GcmListenerService {
String ip = parts[0];
int port = Integer.parseInt(parts[1]);
ConnectionsManager.getInstance().applyDatacenterAddress(dc, ip, port);
} else {
if (ApplicationLoader.mainInterfacePaused) {
int value = bundle.getInt("badge", -1);
if (value == -1) {
} else if ("MESSAGE_ANNOUNCEMENT".equals(key)) {
Object obj = bundle.get("google.sent_time");
long time;
try {
if (obj instanceof String) {
time = Utilities.parseLong((String) obj);
} else if (obj instanceof Long) {
time = (Long) obj;
} else {
time = System.currentTimeMillis();
}
} catch (Exception ignore) {
time = System.currentTimeMillis();
}
TLRPC.TL_updateServiceNotification update = new TLRPC.TL_updateServiceNotification();
update.popup = false;
update.flags = 2;
update.inbox_date = (int) (time / 1000);
update.message = bundle.getString("message");
update.type = "announcement";
update.media = new TLRPC.TL_messageMediaEmpty();
final TLRPC.TL_updates updates = new TLRPC.TL_updates();
updates.updates.add(update);
Utilities.stageQueue.postRunnable(new Runnable() {
@Override
public void run() {
MessagesController.getInstance().processUpdates(updates, false);
}
});
} else if (Build.VERSION.SDK_INT >= 24 && ApplicationLoader.mainInterfacePaused && UserConfig.isClientActivated()) {
Object value = bundle.get("badge");
if (value == null) {
Object obj = bundle.get("google.sent_time");
long time;
if (obj instanceof String) {
time = Utilities.parseLong((String) obj);
} else if (obj instanceof Long) {
time = (Long) obj;
} else {
time = -1;
}
if (time == -1 || UserConfig.lastAppPauseTime < time) {
ConnectivityManager connectivityManager = (ConnectivityManager) ApplicationLoader.applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo netInfo = connectivityManager.getActiveNetworkInfo();
if (netInfo == null || !netInfo.isConnected()) {
if (connectivityManager.getRestrictBackgroundStatus() == RESTRICT_BACKGROUND_STATUS_ENABLED && netInfo.getType() == ConnectivityManager.TYPE_MOBILE) {
NotificationsController.getInstance().showSingleBackgroundNotification();
}
}
......@@ -59,7 +102,6 @@ public class GcmPushListenerService extends GcmListenerService {
} catch (Exception e) {
FileLog.e(e);
}
ConnectionsManager.onInternalPushReceived();
ConnectionsManager.getInstance().resumeNetworkMaybe();
}
......
......@@ -136,8 +136,8 @@ public class ImageLoader {
try {
URL downloadUrl = new URL(url);
httpConnection = downloadUrl.openConnection();
httpConnection.addRequestProperty("User-Agent", "Mozilla/5.0 (Linux; Android 4.4; Nexus 5 Build/_BuildID_) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.0.0 Mobile Safari/537.36");
httpConnection.addRequestProperty("Referer", "google.com");
httpConnection.addRequestProperty("User-Agent", "Mozilla/5.0 (iPhone; CPU iPhone OS 10_0 like Mac OS X) AppleWebKit/602.1.38 (KHTML, like Gecko) Version/10.0 Mobile/14A5297c Safari/602.1");
//httpConnection.addRequestProperty("Referer", "google.com");
httpConnection.setConnectTimeout(5000);
httpConnection.setReadTimeout(5000);
if (httpConnection instanceof HttpURLConnection) {
......@@ -150,8 +150,8 @@ public class ImageLoader {
downloadUrl = new URL(newUrl);
httpConnection = downloadUrl.openConnection();
httpConnection.setRequestProperty("Cookie", cookies);
httpConnection.addRequestProperty("User-Agent", "Mozilla/5.0 (Linux; Android 4.4; Nexus 5 Build/_BuildID_) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.0.0 Mobile Safari/537.36");
httpConnection.addRequestProperty("Referer", "google.com");
httpConnection.addRequestProperty("User-Agent", "Mozilla/5.0 (iPhone; CPU iPhone OS 10_0 like Mac OS X) AppleWebKit/602.1.38 (KHTML, like Gecko) Version/10.0 Mobile/14A5297c Safari/602.1");
//httpConnection.addRequestProperty("Referer", "google.com");
}
}
httpConnection.connect();
......@@ -311,8 +311,8 @@ public class ImageLoader {
try {
URL downloadUrl = new URL(cacheImage.httpUrl);
httpConnection = downloadUrl.openConnection();
httpConnection.addRequestProperty("User-Agent", "Mozilla/5.0 (Linux; Android 4.4; Nexus 5 Build/_BuildID_) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.0.0 Mobile Safari/537.36");
httpConnection.addRequestProperty("Referer", "google.com");
httpConnection.addRequestProperty("User-Agent", "Mozilla/5.0 (iPhone; CPU iPhone OS 10_0 like Mac OS X) AppleWebKit/602.1.38 (KHTML, like Gecko) Version/10.0 Mobile/14A5297c Safari/602.1");
//httpConnection.addRequestProperty("Referer", "google.com");
httpConnection.setConnectTimeout(5000);
httpConnection.setReadTimeout(5000);
if (httpConnection instanceof HttpURLConnection) {
......@@ -1714,15 +1714,16 @@ public class ImageLoader {
}
if (thumb != 2) {
boolean isEncrypted = imageLocation instanceof TLRPC.TL_documentEncrypted || imageLocation instanceof TLRPC.TL_fileEncryptedLocation;
CacheImage img = new CacheImage();
if (httpLocation != null && !httpLocation.startsWith("vthumb") && !httpLocation.startsWith("thumb") && (httpLocation.endsWith("mp4") || httpLocation.endsWith("gif")) ||
imageLocation instanceof TLRPC.TL_webDocument && ((TLRPC.TL_webDocument) imageLocation).mime_type.equals("image/gif") ||
imageLocation instanceof TLRPC.Document && MessageObject.isGifDocument((TLRPC.Document) imageLocation)) {
imageLocation instanceof TLRPC.Document && (MessageObject.isGifDocument((TLRPC.Document) imageLocation) || MessageObject.isRoundVideoDocument((TLRPC.Document) imageLocation))) {
img.animatedFile = true;
}
if (cacheFile == null) {
if (cacheOnly || size == 0 || httpLocation != null) {
if (cacheOnly || size == 0 || httpLocation != null || isEncrypted) {
cacheFile = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE), url);
} else if (imageLocation instanceof TLRPC.Document) {
if (MessageObject.isVideoDocument((TLRPC.Document) imageLocation)) {
......@@ -1867,7 +1868,7 @@ public class ImageLoader {
if (thumbKey != null) {
thumbUrl = thumbKey + "." + ext;
}
saveImageToCache = !MessageObject.isGifDocument(document);
saveImageToCache = !MessageObject.isGifDocument(document) && !MessageObject.isRoundVideoDocument((TLRPC.Document) imageLocation);
}
if (imageLocation == thumbLocation) {
imageLocation = null;
......@@ -2099,6 +2100,13 @@ public class ImageLoader {
}
bmOptions.inJustDecodeBounds = false;
bmOptions.inSampleSize = (int) scaleFactor;
if (bmOptions.inSampleSize % 2 != 0) {
int sample = 1;
while (sample * 2 < bmOptions.inSampleSize) {
sample *= 2;
}
bmOptions.inSampleSize = sample;
}
bmOptions.inPurgeable = Build.VERSION.SDK_INT < 21;
String exifPath = null;
......
......@@ -68,6 +68,7 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg
private Drawable currentThumb;
private Drawable staticThumb;
private boolean allowStartAnimation = true;
private boolean allowDecodeSingleFrame;
private boolean needsQualityThumb;
private boolean shouldGenerateQualityThumb;
......@@ -378,6 +379,9 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg
public boolean onAttachedToWindow() {
NotificationCenter.getInstance().addObserver(this, NotificationCenter.didReplacedPhotoInMemCache);
if (needsQualityThumb) {
NotificationCenter.getInstance().addObserver(this, NotificationCenter.messageThumbGenerated);
}
if (setImageBackup != null && (setImageBackup.fileLocation != null || setImageBackup.httpUrl != null || setImageBackup.thumbLocation != null || setImageBackup.thumb != null)) {
setImage(setImageBackup.fileLocation, setImageBackup.httpUrl, setImageBackup.filter, setImageBackup.thumb, setImageBackup.thumbLocation, setImageBackup.thumbFilter, setImageBackup.size, setImageBackup.ext, setImageBackup.cacheOnly);
return true;
......@@ -676,6 +680,10 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg
return false;
}
public float getCurrentAlpha() {
return currentAlpha;
}
public Bitmap getBitmap() {
if (currentImage instanceof AnimatedFileDrawable) {
return ((AnimatedFileDrawable) currentImage).getAnimatedBitmap();
......@@ -698,6 +706,12 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg
return orientation % 360 == 0 || orientation % 360 == 180 ? staticThumb.getIntrinsicWidth() : staticThumb.getIntrinsicHeight();
}
Bitmap bitmap = getBitmap();
if (bitmap == null) {
if (staticThumb != null) {
return staticThumb.getIntrinsicWidth();
}
return 1;
}
return orientation % 360 == 0 || orientation % 360 == 180 ? bitmap.getWidth() : bitmap.getHeight();
}
......@@ -708,6 +722,12 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg
return orientation % 360 == 0 || orientation % 360 == 180 ? staticThumb.getIntrinsicHeight() : staticThumb.getIntrinsicWidth();
}
Bitmap bitmap = getBitmap();
if (bitmap == null) {
if (staticThumb != null) {
return staticThumb.getIntrinsicHeight();
}
return 1;
}
return orientation % 360 == 0 || orientation % 360 == 180 ? bitmap.getHeight() : bitmap.getWidth();
}
......@@ -768,6 +788,14 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg
imageH = height;
}
public float getCenterX() {
return imageX + imageW / 2.0f;
}
public float getCenterY() {
return imageY + imageH / 2.0f;
}
public int getImageX() {
return imageX;
}
......@@ -889,6 +917,10 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg
allowStartAnimation = value;
}
public void setAllowDecodeSingleFrame(boolean value) {
allowDecodeSingleFrame = value;
}
public boolean isAllowStartAnimation() {
return allowStartAnimation;
}
......@@ -966,6 +998,8 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg
fileDrawable.setParentView(parentView);
if (allowStartAnimation) {
fileDrawable.start();
} else {
fileDrawable.setAllowDecodeSingleFrame(allowDecodeSingleFrame);
}
}
......@@ -984,7 +1018,7 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg
currentThumb = bitmap;
if (roundRadius != 0 && currentImage == null && bitmap instanceof BitmapDrawable) {
if (roundRadius != 0 && bitmap instanceof BitmapDrawable) {
if (bitmap instanceof AnimatedFileDrawable) {
((AnimatedFileDrawable) bitmap).setRoundRadius(roundRadius);
} else {
......@@ -996,9 +1030,13 @@ public class ImageReceiver implements NotificationCenter.NotificationCenterDeleg
}
if (!memCache && crossfadeAlpha != 2) {
currentAlpha = 0.0f;
lastUpdateAlphaTime = System.currentTimeMillis();
crossfadeWithThumb = staticThumb != null && currentKey == null;
if (parentMessageObject != null && parentMessageObject.isRoundVideo() && parentMessageObject.isSending()) {
currentAlpha = 1.0f;
} else {
currentAlpha = 0.0f;
lastUpdateAlphaTime = System.currentTimeMillis();
crossfadeWithThumb = staticThumb != null && currentKey == null;
}
} else {
currentAlpha = 1.0f;
}
......
/*
* This is the source code of Telegram for Android v. 3.x.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-2017.
*/
package org.telegram.messenger;
public class Intro {
public static native void on_draw_frame();
public static native void set_scroll_offset(float a_offset);
public static native void set_page(int page);
public static native void set_date(float a);
public static native void set_date0(float a);
public static native void set_pages_textures(int a1, int a2, int a3, int a4, int a5, int a6);
public static native void set_ic_textures(int a_ic_bubble_dot, int a_ic_bubble, int a_ic_cam_lens, int a_ic_cam, int a_ic_pencil, int a_ic_pin, int a_ic_smile_eye, int a_ic_smile, int a_ic_videocam);
public static native void set_telegram_textures(int a_telegram_sphere, int a_telegram_plane);
public static native void set_fast_textures(int a_fast_body, int a_fast_spiral, int a_fast_arrow, int a_fast_arrow_shadow);
public static native void set_free_textures(int a_knot_up, int a_knot_down);
public static native void set_powerful_textures(int a_powerful_mask, int a_powerful_star, int a_powerful_infinity, int a_powerful_infinity_white);
public static native void set_private_textures(int a_private_door, int a_private_screw);
public static native void on_surface_created();
public static native void on_surface_changed(int a_width_px, int a_height_px, float a_scale_factor, int a1, int a2, int a3, int a4, int a5);
}
......@@ -4008,7 +4008,8 @@ public class MessagesStorage {
if (message instanceof TLRPC.TL_message_secret && (
message.media instanceof TLRPC.TL_messageMediaPhoto && message.ttl > 0 && message.ttl <= 60 ||
MessageObject.isVoiceMessage(message) ||
MessageObject.isVideoMessage(message))) {
MessageObject.isVideoMessage(message) ||
MessageObject.isRoundVideoMessage(message))) {
return 1;
} else if (message.media instanceof TLRPC.TL_messageMediaPhoto || MessageObject.isVideoMessage(message)) {
return 0;
......@@ -4437,13 +4438,21 @@ public class MessagesStorage {
long id = 0;
TLRPC.MessageMedia object = null;
if (MessageObject.isVoiceMessage(message)) {
if ((downloadMask & MediaController.AUTODOWNLOAD_MASK_AUDIO) != 0 && message.media.document.size < 1024 * 1024 * 5) {
if ((downloadMask & MediaController.AUTODOWNLOAD_MASK_AUDIO) != 0 && message.media.document.size < 1024 * 1024 * 2) {
id = message.media.document.id;
type = MediaController.AUTODOWNLOAD_MASK_AUDIO;
object = new TLRPC.TL_messageMediaDocument();
object.caption = "";
object.document = message.media.document;
}
} else if (MessageObject.isRoundVideoMessage(message)) {
if ((downloadMask & MediaController.AUTODOWNLOAD_MASK_VIDEOMESSAGE) != 0 && message.media.document.size < 1024 * 1024 * 5) {
id = message.media.document.id;
type = MediaController.AUTODOWNLOAD_MASK_VIDEOMESSAGE;
object = new TLRPC.TL_messageMediaDocument();
object.caption = "";
object.document = message.media.document;
}
} else if (message.media instanceof TLRPC.TL_messageMediaPhoto) {
if ((downloadMask & MediaController.AUTODOWNLOAD_MASK_PHOTO) != 0) {
TLRPC.PhotoSize photoSize = FileLoader.getClosestPhotoSizeWithSize(message.media.photo.sizes, AndroidUtilities.getPhotoSize());
......@@ -6056,36 +6065,9 @@ public class MessagesStorage {
}
cursor.dispose();
if (!unpinnedDialogs.isEmpty()) {
int minDate = 0;
cursor = database.queryFinalized("SELECT min(date), min(date_i) FROM dialogs WHERE (date != 0 OR date_i != 0) AND pinned = 0");
if (cursor.next()) {
int date = cursor.intValue(0);
int date_i = cursor.intValue(1);
if (date != 0 && date_i != 0) {
minDate = Math.min(date, date_i);
} else if (date == 0) {
minDate = date_i;
} else {
minDate = date;
}
}
cursor.dispose();
SQLitePreparedStatement state = database.executeFast("UPDATE dialogs SET pinned = ? WHERE did = ?");
for (int a = 0; a < unpinnedDialogs.size(); a++) {
long did = unpinnedDialogs.get(a);
int dialogDate = 0;
cursor = database.queryFinalized("SELECT date FROM dialogs WHERE did = " + did);
if (cursor.next()) {
dialogDate = cursor.intValue(0);
}
cursor.dispose();
if (dialogDate <= minDate) {
database.executeFast("DELETE FROM dialogs WHERE did = " + did).stepThis().dispose();
continue;
}
state.requery();
state.bindInteger(1, 0);
state.bindLong(2, did);
......@@ -6105,24 +6087,6 @@ public class MessagesStorage {
@Override
public void run() {
try {
if (pinned == 0 && (int) did != 0) {
int dialogDate = 0;
int minDate = 0;
SQLiteCursor cursor = database.queryFinalized("SELECT date FROM dialogs WHERE did = " + did);
if (cursor.next()) {
dialogDate = cursor.intValue(0);
}
cursor.dispose();
cursor = database.queryFinalized("SELECT min(date) FROM dialogs WHERE date != 0 AND pinned = 0");
if (cursor.next()) {
minDate = cursor.intValue(0);
}
cursor.dispose();
if (dialogDate <= minDate) {
database.executeFast("DELETE FROM dialogs WHERE did = " + did).stepThis().dispose();
return;
}
}
SQLitePreparedStatement state = database.executeFast("UPDATE dialogs SET pinned = ? WHERE did = ?");
state.bindInteger(1, pinned);
state.bindLong(2, did);
......
......@@ -108,9 +108,9 @@ public class MusicBrowserService extends MediaBrowserService implements Notifica
updatePlaybackState(null);
NotificationCenter.getInstance().addObserver(this, NotificationCenter.audioPlayStateChanged);
NotificationCenter.getInstance().addObserver(this, NotificationCenter.audioDidStarted);
NotificationCenter.getInstance().addObserver(this, NotificationCenter.audioDidReset);
NotificationCenter.getInstance().addObserver(this, NotificationCenter.messagePlayingPlayStateChanged);
NotificationCenter.getInstance().addObserver(this, NotificationCenter.messagePlayingDidStarted);
NotificationCenter.getInstance().addObserver(this, NotificationCenter.messagePlayingDidReset);
}
@Override
......@@ -363,7 +363,7 @@ public class MusicBrowserService extends MediaBrowserService implements Notifica
if (messageObject == null) {
onPlayFromMediaId(lastSelectedDialog + "_" + 0, null);
} else {
MediaController.getInstance().playAudio(messageObject);
MediaController.getInstance().playMessage(messageObject);
}
}
......@@ -486,7 +486,7 @@ public class MusicBrowserService extends MediaBrowserService implements Notifica
if (MediaController.getInstance().isDownloadingCurrentMessage()) {
state = PlaybackState.STATE_BUFFERING;
} else {
state = MediaController.getInstance().isAudioPaused() ? PlaybackState.STATE_PAUSED : PlaybackState.STATE_PLAYING;
state = MediaController.getInstance().isMessagePaused() ? PlaybackState.STATE_PAUSED : PlaybackState.STATE_PLAYING;
}
}
......@@ -508,7 +508,7 @@ public class MusicBrowserService extends MediaBrowserService implements Notifica
long actions = PlaybackState.ACTION_PLAY | PlaybackState.ACTION_PLAY_FROM_MEDIA_ID | PlaybackState.ACTION_PLAY_FROM_SEARCH;
MessageObject playingMessageObject = MediaController.getInstance().getPlayingMessageObject();
if (playingMessageObject != null) {
if (!MediaController.getInstance().isAudioPaused()) {
if (!MediaController.getInstance().isMessagePaused()) {
actions |= PlaybackState.ACTION_PAUSE;
}
actions |= PlaybackState.ACTION_SKIP_TO_PREVIOUS;
......@@ -523,9 +523,9 @@ public class MusicBrowserService extends MediaBrowserService implements Notifica
updatePlaybackState(withError);
stopSelf();
serviceStarted = false;
NotificationCenter.getInstance().removeObserver(this, NotificationCenter.audioPlayStateChanged);
NotificationCenter.getInstance().removeObserver(this, NotificationCenter.audioDidStarted);
NotificationCenter.getInstance().removeObserver(this, NotificationCenter.audioDidReset);
NotificationCenter.getInstance().removeObserver(this, NotificationCenter.messagePlayingPlayStateChanged);
NotificationCenter.getInstance().removeObserver(this, NotificationCenter.messagePlayingDidStarted);
NotificationCenter.getInstance().removeObserver(this, NotificationCenter.messagePlayingDidReset);
}
private void handlePlayRequest() {
......@@ -558,7 +558,7 @@ public class MusicBrowserService extends MediaBrowserService implements Notifica
}
private void handlePauseRequest() {
MediaController.getInstance().pauseAudio(MediaController.getInstance().getPlayingMessageObject());
MediaController.getInstance().pauseMessage(MediaController.getInstance().getPlayingMessageObject());
delayedStopHandler.removeCallbacksAndMessages(null);
delayedStopHandler.sendEmptyMessageDelayed(0, STOP_DELAY);
}
......@@ -581,7 +581,7 @@ public class MusicBrowserService extends MediaBrowserService implements Notifica
MusicBrowserService service = mWeakReference.get();
if (service != null) {
MessageObject messageObject = MediaController.getInstance().getPlayingMessageObject();
if (messageObject != null && !MediaController.getInstance().isAudioPaused()) {
if (messageObject != null && !MediaController.getInstance().isMessagePaused()) {
return;
}
service.stopSelf();
......
......@@ -31,17 +31,17 @@ public class MusicPlayerReceiver extends BroadcastReceiver {
switch (keyEvent.getKeyCode()) {
case KeyEvent.KEYCODE_HEADSETHOOK:
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
if (MediaController.getInstance().isAudioPaused()) {
MediaController.getInstance().playAudio(MediaController.getInstance().getPlayingMessageObject());
if (MediaController.getInstance().isMessagePaused()) {
MediaController.getInstance().playMessage(MediaController.getInstance().getPlayingMessageObject());
} else {
MediaController.getInstance().pauseAudio(MediaController.getInstance().getPlayingMessageObject());
MediaController.getInstance().pauseMessage(MediaController.getInstance().getPlayingMessageObject());
}
break;
case KeyEvent.KEYCODE_MEDIA_PLAY:
MediaController.getInstance().playAudio(MediaController.getInstance().getPlayingMessageObject());
MediaController.getInstance().playMessage(MediaController.getInstance().getPlayingMessageObject());
break;
case KeyEvent.KEYCODE_MEDIA_PAUSE:
MediaController.getInstance().pauseAudio(MediaController.getInstance().getPlayingMessageObject());
MediaController.getInstance().pauseMessage(MediaController.getInstance().getPlayingMessageObject());
break;
case KeyEvent.KEYCODE_MEDIA_STOP:
break;
......@@ -54,9 +54,9 @@ public class MusicPlayerReceiver extends BroadcastReceiver {
}
} else {
if (intent.getAction().equals(MusicPlayerService.NOTIFY_PLAY)) {
MediaController.getInstance().playAudio(MediaController.getInstance().getPlayingMessageObject());
MediaController.getInstance().playMessage(MediaController.getInstance().getPlayingMessageObject());
} else if (intent.getAction().equals(MusicPlayerService.NOTIFY_PAUSE) || intent.getAction().equals(android.media.AudioManager.ACTION_AUDIO_BECOMING_NOISY)) {
MediaController.getInstance().pauseAudio(MediaController.getInstance().getPlayingMessageObject());
MediaController.getInstance().pauseMessage(MediaController.getInstance().getPlayingMessageObject());
} else if (intent.getAction().equals(MusicPlayerService.NOTIFY_NEXT)) {
MediaController.getInstance().playNextMessage();
} else if (intent.getAction().equals(MusicPlayerService.NOTIFY_CLOSE)) {
......
......@@ -49,8 +49,8 @@ public class MusicPlayerService extends Service implements NotificationCenter.No
@Override
public void onCreate() {
audioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
NotificationCenter.getInstance().addObserver(this, NotificationCenter.audioProgressDidChanged);
NotificationCenter.getInstance().addObserver(this, NotificationCenter.audioPlayStateChanged);
NotificationCenter.getInstance().addObserver(this, NotificationCenter.messagePlayingProgressDidChanged);
NotificationCenter.getInstance().addObserver(this, NotificationCenter.messagePlayingPlayStateChanged);
super.onCreate();
}
......@@ -159,7 +159,7 @@ public class MusicPlayerService extends Service implements NotificationCenter.No
notification.bigContentView.setViewVisibility(R.id.player_progress_bar, View.GONE);
}
if (MediaController.getInstance().isAudioPaused()) {
if (MediaController.getInstance().isMessagePaused()) {
notification.contentView.setViewVisibility(R.id.player_pause, View.GONE);
notification.contentView.setViewVisibility(R.id.player_play, View.VISIBLE);
if (supportBigNotifications) {
......@@ -223,13 +223,13 @@ public class MusicPlayerService extends Service implements NotificationCenter.No
metadataEditor.apply();
audioManager.unregisterRemoteControlClient(remoteControlClient);
}
NotificationCenter.getInstance().removeObserver(this, NotificationCenter.audioProgressDidChanged);
NotificationCenter.getInstance().removeObserver(this, NotificationCenter.audioPlayStateChanged);
NotificationCenter.getInstance().removeObserver(this, NotificationCenter.messagePlayingProgressDidChanged);
NotificationCenter.getInstance().removeObserver(this, NotificationCenter.messagePlayingPlayStateChanged);
}
@Override
public void didReceivedNotification(int id, Object... args) {
if (id == NotificationCenter.audioPlayStateChanged) {
if (id == NotificationCenter.messagePlayingPlayStateChanged) {
MessageObject messageObject = MediaController.getInstance().getPlayingMessageObject();
if (messageObject != null) {
createNotification(messageObject);
......
......@@ -23,7 +23,7 @@ import java.util.zip.ZipFile;
public class NativeLoader {
private final static int LIB_VERSION = 26;
private final static int LIB_VERSION = 27;
private final static String LIB_NAME = "tmessages." + LIB_VERSION;
private final static String LIB_SO_NAME = "lib" + LIB_NAME + ".so";
private final static String LOCALE_LIB_SO_NAME = "lib" + LIB_NAME + "loc.so";
......
......@@ -82,6 +82,10 @@ public class NotificationCenter {
public static final int didSetNewWallpapper = totalEvents++;
public static final int archivedStickersCountDidLoaded = totalEvents++;
public static final int paymentFinished = totalEvents++;
public static final int reloadInterface = totalEvents++;
public static final int suggestedLangpack = totalEvents++;
public static final int channelRightsUpdated = totalEvents++;
public static final int proxySettingsChanged = totalEvents++;
public static final int httpFileDidLoaded = totalEvents++;
public static final int httpFileDidFailedLoad = totalEvents++;
......@@ -106,9 +110,10 @@ public class NotificationCenter {
public static final int FileNewChunkAvailable = totalEvents++;
public static final int FilePreparingFailed = totalEvents++;
public static final int audioProgressDidChanged = totalEvents++;
public static final int audioDidReset = totalEvents++;
public static final int audioPlayStateChanged = totalEvents++;
public static final int messagePlayingProgressDidChanged = totalEvents++;
public static final int messagePlayingDidReset = totalEvents++;
public static final int messagePlayingPlayStateChanged = totalEvents++;
public static final int messagePlayingDidStarted = totalEvents++;
public static final int recordProgressChanged = totalEvents++;
public static final int recordStarted = totalEvents++;
public static final int recordStartError = totalEvents++;
......@@ -116,7 +121,6 @@ public class NotificationCenter {
public static final int screenshotTook = totalEvents++;
public static final int albumsDidLoaded = totalEvents++;
public static final int audioDidSent = totalEvents++;
public static final int audioDidStarted = totalEvents++;
public static final int audioRouteChanged = totalEvents++;
public static final int didStartedCall = totalEvents++;
......
......@@ -928,6 +928,8 @@ public class NotificationsController {
msg = LocaleController.formatString("NotificationMessageGame", R.string.NotificationMessageGame, name, messageObject.messageOwner.media.game.title);
} else if (messageObject.isVoice()) {
msg = LocaleController.formatString("NotificationMessageAudio", R.string.NotificationMessageAudio, name);
} else if (messageObject.isRoundVideo()) {
msg = LocaleController.formatString("NotificationMessageRound", R.string.NotificationMessageRound, name);
} else if (messageObject.isMusic()) {
msg = LocaleController.formatString("NotificationMessageMusic", R.string.NotificationMessageMusic, name);
} else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaContact) {
......@@ -1086,6 +1088,12 @@ public class NotificationsController {
} else {
msg = LocaleController.formatString("NotificationActionPinnedVoiceChannel", R.string.NotificationActionPinnedVoiceChannel, chat.title);
}
} else if (object.isRoundVideo()) {
if (!ChatObject.isChannel(chat) || chat.megagroup) {
msg = LocaleController.formatString("NotificationActionPinnedRound", R.string.NotificationActionPinnedRound, name, chat.title);
} else {
msg = LocaleController.formatString("NotificationActionPinnedRoundChannel", R.string.NotificationActionPinnedRoundChannel, chat.title);
}
} else if (object.isSticker()) {
String emoji = messageObject.getStickerEmoji();
if (emoji != null) {
......@@ -1192,6 +1200,8 @@ public class NotificationsController {
}
} else if (messageObject.isVoice()) {
msg = LocaleController.formatString("ChannelMessageAudio", R.string.ChannelMessageAudio, name);
} else if (messageObject.isRoundVideo()) {
msg = LocaleController.formatString("ChannelMessageRound", R.string.ChannelMessageRound, name);
} else if (messageObject.isMusic()) {
msg = LocaleController.formatString("ChannelMessageMusic", R.string.ChannelMessageMusic, name);
} else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaContact) {
......@@ -1241,6 +1251,8 @@ public class NotificationsController {
}
} else if (messageObject.isVoice()) {
msg = LocaleController.formatString("ChannelMessageGroupAudio", R.string.ChannelMessageGroupAudio, name, chat.title);
} else if (messageObject.isRoundVideo()) {
msg = LocaleController.formatString("ChannelMessageGroupRound", R.string.ChannelMessageGroupRound, name, chat.title);
} else if (messageObject.isMusic()) {
msg = LocaleController.formatString("ChannelMessageGroupMusic", R.string.ChannelMessageGroupMusic, name, chat.title);
} else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaContact) {
......@@ -1291,6 +1303,8 @@ public class NotificationsController {
}
} else if (messageObject.isVoice()) {
msg = LocaleController.formatString("NotificationMessageGroupAudio", R.string.NotificationMessageGroupAudio, name, chat.title);
} else if (messageObject.isRoundVideo()) {
msg = LocaleController.formatString("NotificationMessageGroupRound", R.string.NotificationMessageGroupRound, name, chat.title);
} else if (messageObject.isMusic()) {
msg = LocaleController.formatString("NotificationMessageGroupMusic", R.string.NotificationMessageGroupMusic, name, chat.title);
} else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaContact) {
......
......@@ -38,6 +38,7 @@ public class UserConfig {
public static int autoLockIn = 60 * 60;
public static boolean allowScreenCapture;
public static int lastPauseTime;
public static long lastAppPauseTime;
public static boolean isWaitingForPasscodeEnter;
public static boolean useFingerprint = true;
public static String lastUpdateVersion;
......@@ -55,6 +56,14 @@ public class UserConfig {
public static int migrateOffsetChannelId = -1;
public static long migrateOffsetAccess = -1;
public static int totalDialogsLoadCount = 0;
public static int dialogsLoadOffsetId = 0;
public static int dialogsLoadOffsetDate = 0;
public static int dialogsLoadOffsetUserId = 0;
public static int dialogsLoadOffsetChatId = 0;
public static int dialogsLoadOffsetChannelId = 0;
public static long dialogsLoadOffsetAccess = 0;
public static int getNewMessageId() {
int id;
synchronized (sync) {
......@@ -87,6 +96,7 @@ public class UserConfig {
editor.putInt("passcodeType", passcodeType);
editor.putInt("autoLockIn", autoLockIn);
editor.putInt("lastPauseTime", lastPauseTime);
editor.putLong("lastAppPauseTime", lastAppPauseTime);
editor.putString("lastUpdateVersion2", lastUpdateVersion);
editor.putInt("lastContactsSyncTime", lastContactsSyncTime);
editor.putBoolean("useFingerprint", useFingerprint);
......@@ -96,14 +106,24 @@ public class UserConfig {
editor.putBoolean("allowScreenCapture", allowScreenCapture);
editor.putBoolean("pinnedDialogsLoaded", pinnedDialogsLoaded);
editor.putInt("migrateOffsetId", migrateOffsetId);
editor.putInt("3migrateOffsetId", migrateOffsetId);
if (migrateOffsetId != -1) {
editor.putInt("migrateOffsetDate", migrateOffsetDate);
editor.putInt("migrateOffsetUserId", migrateOffsetUserId);
editor.putInt("migrateOffsetChatId", migrateOffsetChatId);
editor.putInt("migrateOffsetChannelId", migrateOffsetChannelId);
editor.putLong("migrateOffsetAccess", migrateOffsetAccess);
editor.putInt("3migrateOffsetDate", migrateOffsetDate);
editor.putInt("3migrateOffsetUserId", migrateOffsetUserId);
editor.putInt("3migrateOffsetChatId", migrateOffsetChatId);
editor.putInt("3migrateOffsetChannelId", migrateOffsetChannelId);
editor.putLong("3migrateOffsetAccess", migrateOffsetAccess);
}
editor.putInt("2totalDialogsLoadCount", totalDialogsLoadCount);
editor.putInt("2dialogsLoadOffsetId", dialogsLoadOffsetId);
editor.putInt("2dialogsLoadOffsetDate", dialogsLoadOffsetDate);
editor.putInt("2dialogsLoadOffsetUserId", dialogsLoadOffsetUserId);
editor.putInt("2dialogsLoadOffsetChatId", dialogsLoadOffsetChatId);
editor.putInt("2dialogsLoadOffsetChannelId", dialogsLoadOffsetChannelId);
editor.putLong("2dialogsLoadOffsetAccess", dialogsLoadOffsetAccess);
if (tmpPassword != null) {
SerializedData data = new SerializedData();
tmpPassword.serializeToStream(data);
......@@ -236,6 +256,7 @@ public class UserConfig {
passcodeType = preferences.getInt("passcodeType", 0);
autoLockIn = preferences.getInt("autoLockIn", 60 * 60);
lastPauseTime = preferences.getInt("lastPauseTime", 0);
lastAppPauseTime = preferences.getLong("lastAppPauseTime", 0);
useFingerprint = preferences.getBoolean("useFingerprint", true);
lastUpdateVersion = preferences.getString("lastUpdateVersion2", "3.5");
lastContactsSyncTime = preferences.getInt("lastContactsSyncTime", (int) (System.currentTimeMillis() / 1000) - 23 * 60 * 60);
......@@ -249,14 +270,36 @@ public class UserConfig {
lastPauseTime = (int) (System.currentTimeMillis() / 1000 - 60 * 10);
}
migrateOffsetId = preferences.getInt("migrateOffsetId", 0);
migrateOffsetId = preferences.getInt("3migrateOffsetId", 0);
if (migrateOffsetId != -1) {
migrateOffsetDate = preferences.getInt("migrateOffsetDate", 0);
migrateOffsetUserId = preferences.getInt("migrateOffsetUserId", 0);
migrateOffsetChatId = preferences.getInt("migrateOffsetChatId", 0);
migrateOffsetChannelId = preferences.getInt("migrateOffsetChannelId", 0);
migrateOffsetAccess = preferences.getLong("migrateOffsetAccess", 0);
migrateOffsetDate = preferences.getInt("3migrateOffsetDate", 0);
migrateOffsetUserId = preferences.getInt("3migrateOffsetUserId", 0);
migrateOffsetChatId = preferences.getInt("3migrateOffsetChatId", 0);
migrateOffsetChannelId = preferences.getInt("3migrateOffsetChannelId", 0);
migrateOffsetAccess = preferences.getLong("3migrateOffsetAccess", 0);
}
// migrateOffsetId = 0;
// migrateOffsetDate = 0;
// migrateOffsetUserId = 0;
// migrateOffsetChatId = 0;
// migrateOffsetChannelId = 0;
// migrateOffsetAccess = 0;
dialogsLoadOffsetId = preferences.getInt("2dialogsLoadOffsetId", -1);
totalDialogsLoadCount = preferences.getInt("2totalDialogsLoadCount", 0);
dialogsLoadOffsetDate = preferences.getInt("2dialogsLoadOffsetDate", -1);
dialogsLoadOffsetUserId = preferences.getInt("2dialogsLoadOffsetUserId", -1);
dialogsLoadOffsetChatId = preferences.getInt("2dialogsLoadOffsetChatId", -1);
dialogsLoadOffsetChannelId = preferences.getInt("2dialogsLoadOffsetChannelId", -1);
dialogsLoadOffsetAccess = preferences.getLong("2dialogsLoadOffsetAccess", -1);
// dialogsLoadOffsetId = -1;
// totalDialogsLoadCount = 0;
// dialogsLoadOffsetDate = -1;
// dialogsLoadOffsetUserId = -1;
// dialogsLoadOffsetChatId = -1;
// dialogsLoadOffsetChannelId = -1;
// dialogsLoadOffsetAccess = -1;
String string = preferences.getString("tmpPassword", null);
if (string != null) {
......@@ -413,6 +456,13 @@ public class UserConfig {
migrateOffsetChatId = -1;
migrateOffsetChannelId = -1;
migrateOffsetAccess = -1;
dialogsLoadOffsetId = 0;
totalDialogsLoadCount = 0;
dialogsLoadOffsetDate = 0;
dialogsLoadOffsetUserId = 0;
dialogsLoadOffsetChatId = 0;
dialogsLoadOffsetChannelId = 0;
dialogsLoadOffsetAccess = 0;
appLocked = false;
passcodeType = 0;
passcodeHash = "";
......
......@@ -52,6 +52,7 @@ public class Utilities {
public native static boolean loadWebpImage(Bitmap bitmap, ByteBuffer buffer, int len, BitmapFactory.Options options, boolean unpin);
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);
public native static void aesCtrDecryption(ByteBuffer buffer, byte[] key, byte[] iv, int offset, int length);
public native static String readlink(String path);
public static void aesIgeEncryption(ByteBuffer buffer, byte[] key, byte[] iv, boolean encrypt, boolean changeIv, int offset, int length) {
......
......@@ -8,6 +8,8 @@
package org.telegram.messenger;
import org.telegram.tgnet.TLRPC;
import java.util.Locale;
public class VideoEditedInfo {
......@@ -22,6 +24,12 @@ public class VideoEditedInfo {
public String originalPath;
public long estimatedSize;
public long estimatedDuration;
public boolean roundVideo;
public boolean muted;
public TLRPC.InputFile file;
public TLRPC.InputEncryptedFile encryptedFile;
public byte[] key;
public byte[] iv;
public String getString() {
return String.format(Locale.US, "-1_%d_%d_%d_%d_%d_%d_%d_%d_%s", startTime, endTime, rotationValue, originalWidth, originalHeight, bitrate, resultWidth, resultHeight, originalPath);
......@@ -56,4 +64,8 @@ public class VideoEditedInfo {
}
return false;
}
public boolean needConvert() {
return !roundVideo || roundVideo && (startTime > 0 || endTime != -1 && endTime != estimatedDuration);
}
}
......@@ -196,6 +196,14 @@ public class Browser {
public static boolean isInternalUri(Uri uri) {
String host = uri.getHost();
host = host != null ? host.toLowerCase() : "";
return "tg".equals(uri.getScheme()) || "telegram.me".equals(host) || "t.me".equals(host) || "telegram.dog".equals(host);
if ("tg".equals(uri.getScheme())) {
return true;
} else if ("telegram.me".equals(host) || "t.me".equals(host) || "telegram.dog".equals(host) || "telesco.pe".equals(host)) {
String path = uri.getPath();
if (path != null && path.length() > 1) {
return true;
}
}
return false;
}
}
......@@ -41,6 +41,10 @@ public class CameraInfo {
return pictureSizes;
}
public boolean isFrontface() {
return frontCamera != 0;
}
/*private int getScore(CameraSelectionCriteria criteria) {
int score = 10;
if (criteria != null) {
......
......@@ -51,6 +51,7 @@ public class CameraView extends FrameLayout implements TextureView.SurfaceTextur
private float focusProgress = 1.0f;
private float innerAlpha;
private float outerAlpha;
private boolean initialFrontface;
private int cx;
private int cy;
private Paint outerPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
......@@ -65,7 +66,7 @@ public class CameraView extends FrameLayout implements TextureView.SurfaceTextur
public CameraView(Context context, boolean frontface) {
super(context, null);
isFrontface = frontface;
initialFrontface = isFrontface = frontface;
textureView = new TextureView(context);
textureView.setSurfaceTextureListener(this);
addView(textureView);
......@@ -132,14 +133,20 @@ public class CameraView extends FrameLayout implements TextureView.SurfaceTextur
org.telegram.messenger.camera.Size aspectRatio;
int wantedWidth;
int wantedHeight;
if (Math.abs(screenSize - size4to3) < 0.1f) {
aspectRatio = new Size(4, 3);
wantedWidth = 1280;
wantedHeight = 960;
} else {
if (initialFrontface) {
aspectRatio = new Size(16, 9);
wantedWidth = 1280;
wantedHeight = 720;
wantedWidth = 480;
wantedHeight = 270;
} else {
if (Math.abs(screenSize - size4to3) < 0.1f) {
aspectRatio = new Size(4, 3);
wantedWidth = 1280;
wantedHeight = 960;
} else {
aspectRatio = new Size(16, 9);
wantedWidth = 1280;
wantedHeight = 720;
}
}
if (textureView.getWidth() > 0 && textureView.getHeight() > 0) {
int width = Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y);
......
......@@ -67,6 +67,6 @@ public final class Size {
return mHeight ^ ((mWidth << (Integer.SIZE / 2)) | (mWidth >>> (Integer.SIZE / 2)));
}
private final int mWidth;
private final int mHeight;
public final int mWidth;
public final int mHeight;
}
......@@ -56,8 +56,7 @@ public final class ExoPlaybackException extends Exception {
* The type of the playback failure. One of {@link #TYPE_SOURCE}, {@link #TYPE_RENDERER} and
* {@link #TYPE_UNEXPECTED}.
*/
@Type
public final int type;
@Type public final int type;
/**
* If {@link #type} is {@link #TYPE_RENDERER}, this is the index of the renderer.
......
......@@ -23,6 +23,7 @@ import android.media.MediaDrm;
import android.media.NotProvisionedException;
import android.media.ResourceBusyException;
import android.media.UnsupportedSchemeException;
import android.support.annotation.NonNull;
import org.telegram.messenger.exoplayer2.util.Assertions;
import java.util.HashMap;
import java.util.Map;
......@@ -62,7 +63,8 @@ public final class FrameworkMediaDrm implements ExoMediaDrm<FrameworkMediaCrypto
final ExoMediaDrm.OnEventListener<? super FrameworkMediaCrypto> listener) {
mediaDrm.setOnEventListener(listener == null ? null : new MediaDrm.OnEventListener() {
@Override
public void onEvent(MediaDrm md, byte[] sessionId, int event, int extra, byte[] data) {
public void onEvent(@NonNull MediaDrm md, byte[] sessionId, int event, int extra,
byte[] data) {
listener.onEvent(FrameworkMediaDrm.this, sessionId, event, extra, data);
}
});
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment