update to 9.5.8

This commit is contained in:
xaxtix 2023-04-03 17:15:52 +04:00
parent 7e6d40a77a
commit 683c4e6dcb
25 changed files with 399 additions and 336 deletions

View file

@ -435,7 +435,7 @@ target_include_directories(breakpad PUBLIC
#voip #voip
include(${CMAKE_HOME_DIRECTORY}/voip/CMakeLists.txt) include(${CMAKE_HOME_DIRECTORY}/voip/CMakeLists.txt)
set(NATIVE_LIB "tmessages.43") set(NATIVE_LIB "tmessages.44")
#tmessages #tmessages
add_library(${NATIVE_LIB} SHARED add_library(${NATIVE_LIB} SHARED

View file

@ -13,47 +13,48 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#include <android/log.h>
#include <jni.h> #include <jni.h>
#include <stdlib.h> #include <stdlib.h>
#include <android/log.h>
extern "C" { extern "C" {
#ifdef __cplusplus #ifdef __cplusplus
#define __STDC_CONSTANT_MACROS
#ifdef _STDINT_H #ifdef _STDINT_H
#undef _STDINT_H #undef _STDINT_H
#endif #endif
#include <stdint.h> #include <stdint.h>
#endif #endif
#include <libavcodec/avcodec.h> #include <libavcodec/avcodec.h>
#include <libavresample/avresample.h>
#include <libavutil/channel_layout.h> #include <libavutil/channel_layout.h>
#include <libavutil/error.h> #include <libavutil/error.h>
#include <libavutil/opt.h> #include <libavutil/opt.h>
#include <libswresample/swresample.h>
} }
#define LOG_TAG "ffmpeg_jni" #define LOG_TAG "ffmpeg_jni"
#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, \ #define LOGE(...) \
__VA_ARGS__)) ((void)__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__))
#define DECODER_FUNC(RETURN_TYPE, NAME, ...) \
extern "C" { \
JNIEXPORT RETURN_TYPE \
Java_com_google_android_exoplayer2_ext_ffmpeg_FfmpegDecoder_ ## NAME \
(JNIEnv* env, jobject thiz, ##__VA_ARGS__);\
} \
JNIEXPORT RETURN_TYPE \
Java_com_google_android_exoplayer2_ext_ffmpeg_FfmpegDecoder_ ## NAME \
(JNIEnv* env, jobject thiz, ##__VA_ARGS__)\
#define LIBRARY_FUNC(RETURN_TYPE, NAME, ...) \ #define LIBRARY_FUNC(RETURN_TYPE, NAME, ...) \
extern "C" { \ extern "C" { \
JNIEXPORT RETURN_TYPE \ JNIEXPORT RETURN_TYPE \
Java_com_google_android_exoplayer2_ext_ffmpeg_FfmpegLibrary_ ## NAME \ Java_com_google_android_exoplayer2_ext_ffmpeg_FfmpegLibrary_##NAME( \
(JNIEnv* env, jobject thiz, ##__VA_ARGS__);\ JNIEnv *env, jobject thiz, ##__VA_ARGS__); \
} \ } \
JNIEXPORT RETURN_TYPE \ JNIEXPORT RETURN_TYPE \
Java_com_google_android_exoplayer2_ext_ffmpeg_FfmpegLibrary_ ## NAME \ Java_com_google_android_exoplayer2_ext_ffmpeg_FfmpegLibrary_##NAME( \
(JNIEnv* env, jobject thiz, ##__VA_ARGS__)\ JNIEnv *env, jobject thiz, ##__VA_ARGS__)
#define AUDIO_DECODER_FUNC(RETURN_TYPE, NAME, ...) \
extern "C" { \
JNIEXPORT RETURN_TYPE \
Java_com_google_android_exoplayer2_ext_ffmpeg_FfmpegAudioDecoder_##NAME( \
JNIEnv *env, jobject thiz, ##__VA_ARGS__); \
} \
JNIEXPORT RETURN_TYPE \
Java_com_google_android_exoplayer2_ext_ffmpeg_FfmpegAudioDecoder_##NAME( \
JNIEnv *env, jobject thiz, ##__VA_ARGS__)
#define ERROR_STRING_BUFFER_LENGTH 256 #define ERROR_STRING_BUFFER_LENGTH 256
@ -62,9 +63,8 @@ static const AVSampleFormat OUTPUT_FORMAT_PCM_16BIT = AV_SAMPLE_FMT_S16;
// Output format corresponding to AudioFormat.ENCODING_PCM_FLOAT. // Output format corresponding to AudioFormat.ENCODING_PCM_FLOAT.
static const AVSampleFormat OUTPUT_FORMAT_PCM_FLOAT = AV_SAMPLE_FMT_FLT; static const AVSampleFormat OUTPUT_FORMAT_PCM_FLOAT = AV_SAMPLE_FMT_FLT;
// Error codes matching FfmpegDecoder.java. static const int AUDIO_DECODER_ERROR_INVALID_DATA = -1;
static const int DECODER_ERROR_INVALID_DATA = -1; static const int AUDIO_DECODER_ERROR_OTHER = -2;
static const int DECODER_ERROR_OTHER = -2;
/** /**
* Returns the AVCodec with the specified name, or NULL if it is not available. * Returns the AVCodec with the specified name, or NULL if it is not available.
@ -82,11 +82,17 @@ AVCodecContext *createContext(JNIEnv *env, AVCodec *codec, jbyteArray extraData,
/** /**
* Decodes the packet into the output buffer, returning the number of bytes * Decodes the packet into the output buffer, returning the number of bytes
* written, or a negative DECODER_ERROR constant value in the case of an error. * written, or a negative AUDIO_DECODER_ERROR constant value in the case of an
* error.
*/ */
int decodePacket(AVCodecContext *context, AVPacket *packet, int decodePacket(AVCodecContext *context, AVPacket *packet,
uint8_t *outputBuffer, int outputSize); uint8_t *outputBuffer, int outputSize);
/**
* Transforms ffmpeg AVERROR into a negative AUDIO_DECODER_ERROR constant value.
*/
int transformError(int errorNumber);
/** /**
* Outputs a log message describing the avcodec error number. * Outputs a log message describing the avcodec error number.
*/ */
@ -101,12 +107,17 @@ LIBRARY_FUNC(jstring, ffmpegGetVersion) {
return env->NewStringUTF(LIBAVCODEC_IDENT); return env->NewStringUTF(LIBAVCODEC_IDENT);
} }
LIBRARY_FUNC(jint, ffmpegGetInputBufferPaddingSize) {
return (jint)AV_INPUT_BUFFER_PADDING_SIZE;
}
LIBRARY_FUNC(jboolean, ffmpegHasDecoder, jstring codecName) { LIBRARY_FUNC(jboolean, ffmpegHasDecoder, jstring codecName) {
return getCodecByName(env, codecName) != NULL; return getCodecByName(env, codecName) != NULL;
} }
DECODER_FUNC(jlong, ffmpegInitialize, jstring codecName, jbyteArray extraData, AUDIO_DECODER_FUNC(jlong, ffmpegInitialize, jstring codecName,
jboolean outputFloat, jint rawSampleRate, jint rawChannelCount) { jbyteArray extraData, jboolean outputFloat,
jint rawSampleRate, jint rawChannelCount) {
AVCodec *codec = getCodecByName(env, codecName); AVCodec *codec = getCodecByName(env, codecName);
if (!codec) { if (!codec) {
LOGE("Codec not found."); LOGE("Codec not found.");
@ -116,7 +127,7 @@ DECODER_FUNC(jlong, ffmpegInitialize, jstring codecName, jbyteArray extraData,
rawChannelCount); rawChannelCount);
} }
DECODER_FUNC(jint, ffmpegDecode, jlong context, jobject inputData, AUDIO_DECODER_FUNC(jint, ffmpegDecode, jlong context, jobject inputData,
jint inputSize, jobject outputData, jint outputSize) { jint inputSize, jobject outputData, jint outputSize) {
if (!context) { if (!context) {
LOGE("Context must be non-NULL."); LOGE("Context must be non-NULL.");
@ -144,7 +155,7 @@ DECODER_FUNC(jint, ffmpegDecode, jlong context, jobject inputData,
outputSize); outputSize);
} }
DECODER_FUNC(jint, ffmpegGetChannelCount, jlong context) { AUDIO_DECODER_FUNC(jint, ffmpegGetChannelCount, jlong context) {
if (!context) { if (!context) {
LOGE("Context must be non-NULL."); LOGE("Context must be non-NULL.");
return -1; return -1;
@ -152,7 +163,7 @@ DECODER_FUNC(jint, ffmpegGetChannelCount, jlong context) {
return ((AVCodecContext *)context)->channels; return ((AVCodecContext *)context)->channels;
} }
DECODER_FUNC(jint, ffmpegGetSampleRate, jlong context) { AUDIO_DECODER_FUNC(jint, ffmpegGetSampleRate, jlong context) {
if (!context) { if (!context) {
LOGE("Context must be non-NULL."); LOGE("Context must be non-NULL.");
return -1; return -1;
@ -160,7 +171,7 @@ DECODER_FUNC(jint, ffmpegGetSampleRate, jlong context) {
return ((AVCodecContext *)context)->sample_rate; return ((AVCodecContext *)context)->sample_rate;
} }
DECODER_FUNC(jlong, ffmpegReset, jlong jContext, jbyteArray extraData) { AUDIO_DECODER_FUNC(jlong, ffmpegReset, jlong jContext, jbyteArray extraData) {
AVCodecContext *context = (AVCodecContext *)jContext; AVCodecContext *context = (AVCodecContext *)jContext;
if (!context) { if (!context) {
LOGE("Tried to reset without a context."); LOGE("Tried to reset without a context.");
@ -188,7 +199,7 @@ DECODER_FUNC(jlong, ffmpegReset, jlong jContext, jbyteArray extraData) {
return (jlong)context; return (jlong)context;
} }
DECODER_FUNC(void, ffmpegRelease, jlong context) { AUDIO_DECODER_FUNC(void, ffmpegRelease, jlong context) {
if (context) { if (context) {
releaseContext((AVCodecContext *)context); releaseContext((AVCodecContext *)context);
} }
@ -249,8 +260,7 @@ int decodePacket(AVCodecContext *context, AVPacket *packet,
result = avcodec_send_packet(context, packet); result = avcodec_send_packet(context, packet);
if (result) { if (result) {
logError("avcodec_send_packet", result); logError("avcodec_send_packet", result);
return result == AVERROR_INVALIDDATA ? DECODER_ERROR_INVALID_DATA return transformError(result);
: DECODER_ERROR_OTHER;
} }
// Dequeue output data until it runs out. // Dequeue output data until it runs out.
@ -259,7 +269,7 @@ int decodePacket(AVCodecContext *context, AVPacket *packet,
AVFrame *frame = av_frame_alloc(); AVFrame *frame = av_frame_alloc();
if (!frame) { if (!frame) {
LOGE("Failed to allocate output frame."); LOGE("Failed to allocate output frame.");
return -1; return AUDIO_DECODER_ERROR_INVALID_DATA;
} }
result = avcodec_receive_frame(context, frame); result = avcodec_receive_frame(context, frame);
if (result) { if (result) {
@ -268,7 +278,7 @@ int decodePacket(AVCodecContext *context, AVPacket *packet,
break; break;
} }
logError("avcodec_receive_frame", result); logError("avcodec_receive_frame", result);
return result; return transformError(result);
} }
// Resample output. // Resample output.
@ -279,11 +289,11 @@ int decodePacket(AVCodecContext *context, AVPacket *packet,
int sampleCount = frame->nb_samples; int sampleCount = frame->nb_samples;
int dataSize = av_samples_get_buffer_size(NULL, channelCount, sampleCount, int dataSize = av_samples_get_buffer_size(NULL, channelCount, sampleCount,
sampleFormat, 1); sampleFormat, 1);
AVAudioResampleContext *resampleContext; SwrContext *resampleContext;
if (context->opaque) { if (context->opaque) {
resampleContext = (AVAudioResampleContext *) context->opaque; resampleContext = (SwrContext *)context->opaque;
} else { } else {
resampleContext = avresample_alloc_context(); resampleContext = swr_alloc();
av_opt_set_int(resampleContext, "in_channel_layout", channelLayout, 0); av_opt_set_int(resampleContext, "in_channel_layout", channelLayout, 0);
av_opt_set_int(resampleContext, "out_channel_layout", channelLayout, 0); av_opt_set_int(resampleContext, "out_channel_layout", channelLayout, 0);
av_opt_set_int(resampleContext, "in_sample_rate", sampleRate, 0); av_opt_set_int(resampleContext, "in_sample_rate", sampleRate, 0);
@ -292,37 +302,36 @@ int decodePacket(AVCodecContext *context, AVPacket *packet,
// The output format is always the requested format. // The output format is always the requested format.
av_opt_set_int(resampleContext, "out_sample_fmt", av_opt_set_int(resampleContext, "out_sample_fmt",
context->request_sample_fmt, 0); context->request_sample_fmt, 0);
result = avresample_open(resampleContext); result = swr_init(resampleContext);
if (result < 0) { if (result < 0) {
logError("avresample_open", result); logError("swr_init", result);
av_frame_free(&frame); av_frame_free(&frame);
return -1; return transformError(result);
} }
context->opaque = resampleContext; context->opaque = resampleContext;
} }
int inSampleSize = av_get_bytes_per_sample(sampleFormat); int inSampleSize = av_get_bytes_per_sample(sampleFormat);
int outSampleSize = av_get_bytes_per_sample(context->request_sample_fmt); int outSampleSize = av_get_bytes_per_sample(context->request_sample_fmt);
int outSamples = avresample_get_out_samples(resampleContext, sampleCount); int outSamples = swr_get_out_samples(resampleContext, sampleCount);
int bufferOutSize = outSampleSize * channelCount * outSamples; int bufferOutSize = outSampleSize * channelCount * outSamples;
if (outSize + bufferOutSize > outputSize) { if (outSize + bufferOutSize > outputSize) {
LOGE("Output buffer size (%d) too small for output data (%d).", LOGE("Output buffer size (%d) too small for output data (%d).",
outputSize, outSize + bufferOutSize); outputSize, outSize + bufferOutSize);
av_frame_free(&frame); av_frame_free(&frame);
return -1; return AUDIO_DECODER_ERROR_INVALID_DATA;
} }
result = avresample_convert(resampleContext, &outputBuffer, bufferOutSize, result = swr_convert(resampleContext, &outputBuffer, bufferOutSize,
outSamples, frame->data, frame->linesize[0], (const uint8_t **)frame->data, frame->nb_samples);
sampleCount);
av_frame_free(&frame); av_frame_free(&frame);
if (result < 0) { if (result < 0) {
logError("avresample_convert", result); logError("swr_convert", result);
return result; return AUDIO_DECODER_ERROR_INVALID_DATA;
} }
int available = avresample_available(resampleContext); int available = swr_get_out_samples(resampleContext, 0);
if (available != 0) { if (available != 0) {
LOGE("Expected no samples remaining after resampling, but found %d.", LOGE("Expected no samples remaining after resampling, but found %d.",
available); available);
return -1; return AUDIO_DECODER_ERROR_INVALID_DATA;
} }
outputBuffer += bufferOutSize; outputBuffer += bufferOutSize;
outSize += bufferOutSize; outSize += bufferOutSize;
@ -330,6 +339,11 @@ int decodePacket(AVCodecContext *context, AVPacket *packet,
return outSize; return outSize;
} }
int transformError(int errorNumber) {
return errorNumber == AVERROR_INVALIDDATA ? AUDIO_DECODER_ERROR_INVALID_DATA
: AUDIO_DECODER_ERROR_OTHER;
}
void logError(const char *functionName, int errorNumber) { void logError(const char *functionName, int errorNumber) {
char *buffer = (char *)malloc(ERROR_STRING_BUFFER_LENGTH * sizeof(char)); char *buffer = (char *)malloc(ERROR_STRING_BUFFER_LENGTH * sizeof(char));
av_strerror(errorNumber, buffer, ERROR_STRING_BUFFER_LENGTH); av_strerror(errorNumber, buffer, ERROR_STRING_BUFFER_LENGTH);
@ -341,11 +355,10 @@ void releaseContext(AVCodecContext *context) {
if (!context) { if (!context) {
return; return;
} }
AVAudioResampleContext *resampleContext; SwrContext *swrContext;
if ((resampleContext = (AVAudioResampleContext *) context->opaque)) { if ((swrContext = (SwrContext *)context->opaque)) {
avresample_free(&resampleContext); swr_free(&swrContext);
context->opaque = NULL; context->opaque = NULL;
} }
avcodec_free_context(&context); avcodec_free_context(&context);
} }

View file

@ -47,6 +47,7 @@ public:
if (mid == NULL) { if (mid == NULL) {
jclass cls = env->GetObjectClass(flacDecoderJni); jclass cls = env->GetObjectClass(flacDecoderJni);
mid = env->GetMethodID(cls, "read", "(Ljava/nio/ByteBuffer;)I"); mid = env->GetMethodID(cls, "read", "(Ljava/nio/ByteBuffer;)I");
env->DeleteLocalRef(cls);
} }
} }
@ -57,6 +58,7 @@ public:
// Exception is thrown in Java when returning from the native call. // Exception is thrown in Java when returning from the native call.
result = -1; result = -1;
} }
env->DeleteLocalRef(byteBuffer);
return result; return result;
} }
@ -147,7 +149,7 @@ DECODER_FUNC(jobject, flacDecodeMetadata, jlong jContext) {
context->parser->getStreamInfo(); context->parser->getStreamInfo();
jclass flacStreamMetadataClass = env->FindClass( jclass flacStreamMetadataClass = env->FindClass(
"com/google/android/exoplayer2/util/" "com/google/android/exoplayer2/extractor/"
"FlacStreamMetadata"); "FlacStreamMetadata");
jmethodID flacStreamMetadataConstructor = jmethodID flacStreamMetadataConstructor =
env->GetMethodID(flacStreamMetadataClass, "<init>", env->GetMethodID(flacStreamMetadataClass, "<init>",

View file

@ -16,9 +16,8 @@
#include "include/flac_parser.h" #include "include/flac_parser.h"
#include <jni.h>
#include <android/log.h> #include <android/log.h>
#include <jni.h>
#include <cassert> #include <cassert>
#include <cstdlib> #include <cstdlib>

View file

@ -14,49 +14,60 @@
* limitations under the License. * limitations under the License.
*/ */
#ifdef __ANDROID__
#include <android/log.h>
#endif
#include <jni.h> #include <jni.h>
#include <android/log.h> #include <cstdint>
#include <cstdlib> #include <cstdlib>
#include "opus.h" // NOLINT #include "opus.h" // NOLINT
#include "opus_multistream.h" // NOLINT #include "opus_multistream.h" // NOLINT
#ifdef __ANDROID__
#define LOG_TAG "opus_jni" #define LOG_TAG "opus_jni"
#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, \ #define LOGE(...) \
__VA_ARGS__)) ((void)__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__))
#else // __ANDROID__
#define LOGE(...) \
do { \
} while (0)
#endif // __ANDROID__
#define DECODER_FUNC(RETURN_TYPE, NAME, ...) \ #define DECODER_FUNC(RETURN_TYPE, NAME, ...) \
extern "C" { \ extern "C" { \
JNIEXPORT RETURN_TYPE \ JNIEXPORT RETURN_TYPE \
Java_com_google_android_exoplayer2_ext_opus_OpusDecoder_ ## NAME \ Java_com_google_android_exoplayer2_ext_opus_OpusDecoder_##NAME( \
(JNIEnv* env, jobject thiz, ##__VA_ARGS__);\ JNIEnv* env, jobject thiz, ##__VA_ARGS__); \
} \ } \
JNIEXPORT RETURN_TYPE \ JNIEXPORT RETURN_TYPE \
Java_com_google_android_exoplayer2_ext_opus_OpusDecoder_ ## NAME \ Java_com_google_android_exoplayer2_ext_opus_OpusDecoder_##NAME( \
(JNIEnv* env, jobject thiz, ##__VA_ARGS__)\ JNIEnv* env, jobject thiz, ##__VA_ARGS__)
#define LIBRARY_FUNC(RETURN_TYPE, NAME, ...) \ #define LIBRARY_FUNC(RETURN_TYPE, NAME, ...) \
extern "C" { \ extern "C" { \
JNIEXPORT RETURN_TYPE \ JNIEXPORT RETURN_TYPE \
Java_com_google_android_exoplayer2_ext_opus_OpusLibrary_ ## NAME \ Java_com_google_android_exoplayer2_ext_opus_OpusLibrary_##NAME( \
(JNIEnv* env, jobject thiz, ##__VA_ARGS__);\ JNIEnv* env, jobject thiz, ##__VA_ARGS__); \
} \ } \
JNIEXPORT RETURN_TYPE \ JNIEXPORT RETURN_TYPE \
Java_com_google_android_exoplayer2_ext_opus_OpusLibrary_ ## NAME \ Java_com_google_android_exoplayer2_ext_opus_OpusLibrary_##NAME( \
(JNIEnv* env, jobject thiz, ##__VA_ARGS__)\ JNIEnv* env, jobject thiz, ##__VA_ARGS__)
// JNI references for SimpleOutputBuffer class. // JNI references for SimpleOutputBuffer class.
static jmethodID outputBufferInit; static jmethodID outputBufferInit;
static const int kBytesPerSample = 2; // opus fixed point uses 16 bit samples. static const int kBytesPerIntPcmSample = 2;
static const int kBytesPerFloatSample = 4;
static const int kMaxOpusOutputPacketSizeSamples = 960 * 6; static const int kMaxOpusOutputPacketSizeSamples = 960 * 6;
static int channelCount; static int channelCount;
static int errorCode; static int errorCode;
static bool outputFloat = false;
DECODER_FUNC(jlong, opusInit, jint sampleRate, jint channelCount, DECODER_FUNC(jlong, opusInit, jint sampleRate, jint channelCount,
jint numStreams, jint numCoupled, jint gain, jbyteArray jStreamMap) { jint numStreams, jint numCoupled, jint gain,
jbyteArray jStreamMap) {
int status = OPUS_INVALID_STATE; int status = OPUS_INVALID_STATE;
::channelCount = channelCount; ::channelCount = channelCount;
errorCode = 0; errorCode = 0;
@ -77,9 +88,9 @@ DECODER_FUNC(jlong, opusInit, jint sampleRate, jint channelCount,
// Populate JNI References. // Populate JNI References.
const jclass outputBufferClass = env->FindClass( const jclass outputBufferClass = env->FindClass(
"com/google/android/exoplayer2/decoder/SimpleOutputBuffer"); "com/google/android/exoplayer2/decoder/SimpleDecoderOutputBuffer");
outputBufferInit = env->GetMethodID(outputBufferClass, "init", outputBufferInit =
"(JI)Ljava/nio/ByteBuffer;"); env->GetMethodID(outputBufferClass, "init", "(JI)Ljava/nio/ByteBuffer;");
return reinterpret_cast<intptr_t>(decoder); return reinterpret_cast<intptr_t>(decoder);
} }
@ -87,40 +98,52 @@ DECODER_FUNC(jlong, opusInit, jint sampleRate, jint channelCount,
DECODER_FUNC(jint, opusDecode, jlong jDecoder, jlong jTimeUs, DECODER_FUNC(jint, opusDecode, jlong jDecoder, jlong jTimeUs,
jobject jInputBuffer, jint inputSize, jobject jOutputBuffer) { jobject jInputBuffer, jint inputSize, jobject jOutputBuffer) {
OpusMSDecoder* decoder = reinterpret_cast<OpusMSDecoder*>(jDecoder); OpusMSDecoder* decoder = reinterpret_cast<OpusMSDecoder*>(jDecoder);
const uint8_t* inputBuffer = const uint8_t* inputBuffer = reinterpret_cast<const uint8_t*>(
reinterpret_cast<const uint8_t*>(
env->GetDirectBufferAddress(jInputBuffer)); env->GetDirectBufferAddress(jInputBuffer));
const int byteSizePerSample =
outputFloat ? kBytesPerFloatSample : kBytesPerIntPcmSample;
const jint outputSize = const jint outputSize =
kMaxOpusOutputPacketSizeSamples * kBytesPerSample * channelCount; kMaxOpusOutputPacketSizeSamples * byteSizePerSample * channelCount;
env->CallObjectMethod(jOutputBuffer, outputBufferInit, jTimeUs, outputSize); env->CallObjectMethod(jOutputBuffer, outputBufferInit, jTimeUs, outputSize);
if (env->ExceptionCheck()) { if (env->ExceptionCheck()) {
// Exception is thrown in Java when returning from the native call. // Exception is thrown in Java when returning from the native call.
return -1; return -1;
} }
const jobject jOutputBufferData = env->CallObjectMethod(jOutputBuffer, const jobject jOutputBufferData = env->CallObjectMethod(
outputBufferInit, jTimeUs, outputSize); jOutputBuffer, outputBufferInit, jTimeUs, outputSize);
if (env->ExceptionCheck()) { if (env->ExceptionCheck()) {
// Exception is thrown in Java when returning from the native call. // Exception is thrown in Java when returning from the native call.
return -1; return -1;
} }
int sampleCount;
if (outputFloat) {
float* outputBufferData = reinterpret_cast<float*>(
env->GetDirectBufferAddress(jOutputBufferData));
sampleCount = opus_multistream_decode_float(
decoder, inputBuffer, inputSize, outputBufferData,
kMaxOpusOutputPacketSizeSamples, 0);
} else {
int16_t* outputBufferData = reinterpret_cast<int16_t*>( int16_t* outputBufferData = reinterpret_cast<int16_t*>(
env->GetDirectBufferAddress(jOutputBufferData)); env->GetDirectBufferAddress(jOutputBufferData));
int sampleCount = opus_multistream_decode(decoder, inputBuffer, inputSize, sampleCount = opus_multistream_decode(decoder, inputBuffer, inputSize,
outputBufferData, kMaxOpusOutputPacketSizeSamples, 0); outputBufferData,
kMaxOpusOutputPacketSizeSamples, 0);
}
// record error code // record error code
errorCode = (sampleCount < 0) ? sampleCount : 0; errorCode = (sampleCount < 0) ? sampleCount : 0;
return (sampleCount < 0) ? sampleCount return (sampleCount < 0) ? sampleCount
: sampleCount * kBytesPerSample * channelCount; : sampleCount * byteSizePerSample * channelCount;
} }
DECODER_FUNC(jint, opusSecureDecode, jlong jDecoder, jlong jTimeUs, DECODER_FUNC(jint, opusSecureDecode, jlong jDecoder, jlong jTimeUs,
jobject jInputBuffer, jint inputSize, jobject jOutputBuffer, jobject jInputBuffer, jint inputSize, jobject jOutputBuffer,
jint sampleRate, jobject mediaCrypto, jint inputMode, jbyteArray key, jint sampleRate, jobject mediaCrypto, jint inputMode,
jbyteArray javaIv, jint inputNumSubSamples, jintArray numBytesOfClearData, jbyteArray key, jbyteArray javaIv, jint inputNumSubSamples,
jintArray numBytesOfEncryptedData) { jintArray numBytesOfClearData, jintArray numBytesOfEncryptedData) {
// Doesn't support // Doesn't support
// Java client should have checked vpxSupportSecureDecode // Java client should have checked vpxSupportSecureDecode
// and avoid calling this // and avoid calling this
@ -142,9 +165,9 @@ DECODER_FUNC(jstring, opusGetErrorMessage, jlong jContext) {
return env->NewStringUTF(opus_strerror(errorCode)); return env->NewStringUTF(opus_strerror(errorCode));
} }
DECODER_FUNC(jint, opusGetErrorCode, jlong jContext) { DECODER_FUNC(jint, opusGetErrorCode, jlong jContext) { return errorCode; }
return errorCode;
} DECODER_FUNC(void, opusSetFloatOutput) { outputFloat = true; }
LIBRARY_FUNC(jstring, opusIsSecureDecodeSupported) { LIBRARY_FUNC(jstring, opusIsSecureDecodeSupported) {
// Doesn't support // Doesn't support

View file

@ -23,9 +23,9 @@
-keep class org.telegram.tgnet.QuickAckDelegate { *; } -keep class org.telegram.tgnet.QuickAckDelegate { *; }
-keep class org.telegram.tgnet.WriteToSocketDelegate { *; } -keep class org.telegram.tgnet.WriteToSocketDelegate { *; }
-keep class com.google.android.exoplayer2.ext.** { *; } -keep class com.google.android.exoplayer2.ext.** { *; }
-keep class com.google.android.exoplayer2.util.FlacStreamMetadata { *; } -keep class com.google.android.exoplayer2.extractor.FlacStreamMetadata { *; }
-keep class com.google.android.exoplayer2.metadata.flac.PictureFrame { *; } -keep class com.google.android.exoplayer2.metadata.flac.PictureFrame { *; }
-keep class com.google.android.exoplayer2.decoder.SimpleOutputBuffer { *; } -keep class com.google.android.exoplayer2.decoder.SimpleDecoderOutputBuffer { *; }
# https://developers.google.com/ml-kit/known-issues#android_issues # https://developers.google.com/ml-kit/known-issues#android_issues
-keep class com.google.mlkit.nl.languageid.internal.LanguageIdentificationJni { *; } -keep class com.google.mlkit.nl.languageid.internal.LanguageIdentificationJni { *; }
@ -42,7 +42,7 @@
} }
# Some members of this class are being accessed from native methods. Keep them unobfuscated. # Some members of this class are being accessed from native methods. Keep them unobfuscated.
-keep class com.google.android.exoplayer2.video.VideoDecoderOutputBuffer { -keep class com.google.android.exoplayer2.decoder.VideoDecoderOutputBuffer {
*; *;
} }

View file

@ -2229,6 +2229,10 @@ public class LinearLayoutManager extends RecyclerView.LayoutManager implements
} }
} }
public boolean hasPendingScrollPosition() {
return mPendingScrollPosition >= 0;
}
/** /**
* Helper class that keeps temporary state while {LayoutManager} is filling out the empty * Helper class that keeps temporary state while {LayoutManager} is filling out the empty
* space. * space.

View file

@ -22,6 +22,7 @@ import com.google.android.exoplayer2.util.LibraryLoader;
import com.google.android.exoplayer2.util.Log; import com.google.android.exoplayer2.util.Log;
import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.MimeTypes;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import org.telegram.messenger.NativeLoader;
/** Configures and queries the underlying native library. */ /** Configures and queries the underlying native library. */
public final class FfmpegLibrary { public final class FfmpegLibrary {
@ -32,14 +33,6 @@ public final class FfmpegLibrary {
private static final String TAG = "FfmpegLibrary"; private static final String TAG = "FfmpegLibrary";
private static final LibraryLoader LOADER =
new LibraryLoader("ffmpegJNI") {
@Override
protected void loadLibrary(String name) {
System.loadLibrary(name);
}
};
private static @MonotonicNonNull String version; private static @MonotonicNonNull String version;
private static int inputBufferPaddingSize = C.LENGTH_UNSET; private static int inputBufferPaddingSize = C.LENGTH_UNSET;
@ -53,12 +46,12 @@ public final class FfmpegLibrary {
* @param libraries The names of the FFmpeg native libraries. * @param libraries The names of the FFmpeg native libraries.
*/ */
public static void setLibraries(String... libraries) { public static void setLibraries(String... libraries) {
LOADER.setLibraries(libraries);
} }
/** Returns whether the underlying library is available, loading it if necessary. */ /** Returns whether the underlying library is available, loading it if necessary. */
public static boolean isAvailable() { public static boolean isAvailable() {
return LOADER.isAvailable(); return NativeLoader.loaded();
} }
/** Returns the version of the underlying library if available, or null otherwise. */ /** Returns the version of the underlying library if available, or null otherwise. */

View file

@ -18,6 +18,8 @@ package com.google.android.exoplayer2.ext.flac;
import com.google.android.exoplayer2.ExoPlayerLibraryInfo; import com.google.android.exoplayer2.ExoPlayerLibraryInfo;
import com.google.android.exoplayer2.util.LibraryLoader; import com.google.android.exoplayer2.util.LibraryLoader;
import org.telegram.messenger.NativeLoader;
/** Configures and queries the underlying native library. */ /** Configures and queries the underlying native library. */
public final class FlacLibrary { public final class FlacLibrary {
@ -25,13 +27,6 @@ public final class FlacLibrary {
ExoPlayerLibraryInfo.registerModule("goog.exo.flac"); ExoPlayerLibraryInfo.registerModule("goog.exo.flac");
} }
private static final LibraryLoader LOADER =
new LibraryLoader("flacJNI") {
@Override
protected void loadLibrary(String name) {
System.loadLibrary(name);
}
};
private FlacLibrary() {} private FlacLibrary() {}
@ -43,11 +38,10 @@ public final class FlacLibrary {
* @param libraries The names of the Flac native libraries. * @param libraries The names of the Flac native libraries.
*/ */
public static void setLibraries(String... libraries) { public static void setLibraries(String... libraries) {
LOADER.setLibraries(libraries);
} }
/** Returns whether the underlying library is available, loading it if necessary. */ /** Returns whether the underlying library is available, loading it if necessary. */
public static boolean isAvailable() { public static boolean isAvailable() {
return LOADER.isAvailable(); return NativeLoader.loaded();
} }
} }

View file

@ -20,6 +20,8 @@ import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ExoPlayerLibraryInfo; import com.google.android.exoplayer2.ExoPlayerLibraryInfo;
import com.google.android.exoplayer2.util.LibraryLoader; import com.google.android.exoplayer2.util.LibraryLoader;
import org.telegram.messenger.NativeLoader;
/** Configures and queries the underlying native library. */ /** Configures and queries the underlying native library. */
public final class OpusLibrary { public final class OpusLibrary {
@ -27,14 +29,6 @@ public final class OpusLibrary {
ExoPlayerLibraryInfo.registerModule("goog.exo.opus"); ExoPlayerLibraryInfo.registerModule("goog.exo.opus");
} }
private static final LibraryLoader LOADER =
new LibraryLoader("opusV2JNI") {
@Override
protected void loadLibrary(String name) {
System.loadLibrary(name);
}
};
private static @C.CryptoType int cryptoType = C.CRYPTO_TYPE_UNSUPPORTED; private static @C.CryptoType int cryptoType = C.CRYPTO_TYPE_UNSUPPORTED;
private OpusLibrary() {} private OpusLibrary() {}
@ -51,12 +45,11 @@ public final class OpusLibrary {
*/ */
public static void setLibraries(@C.CryptoType int cryptoType, String... libraries) { public static void setLibraries(@C.CryptoType int cryptoType, String... libraries) {
OpusLibrary.cryptoType = cryptoType; OpusLibrary.cryptoType = cryptoType;
LOADER.setLibraries(libraries);
} }
/** Returns whether the underlying library is available, loading it if necessary. */ /** Returns whether the underlying library is available, loading it if necessary. */
public static boolean isAvailable() { public static boolean isAvailable() {
return LOADER.isAvailable(); return NativeLoader.loaded();
} }
/** Returns the version of the underlying library if available, or null otherwise. */ /** Returns the version of the underlying library if available, or null otherwise. */

View file

@ -15,6 +15,8 @@
*/ */
package com.google.android.exoplayer2.util; package com.google.android.exoplayer2.util;
import static java.lang.System.loadLibrary;
import java.util.Arrays; import java.util.Arrays;
/** Configurable loader for native libraries. */ /** Configurable loader for native libraries. */
@ -72,5 +74,5 @@ public abstract class LibraryLoader {
* *
* @param name The name of the library to load. * @param name The name of the library to load.
*/ */
protected abstract void loadLibrary(String name); protected abstract void oadLibrary(String name);
} }

View file

@ -256,7 +256,11 @@ public class ApplicationLoader extends Application {
} }
NativeLoader.initNativeLibs(ApplicationLoader.applicationContext); NativeLoader.initNativeLibs(ApplicationLoader.applicationContext);
try {
ConnectionsManager.native_setJava(false); ConnectionsManager.native_setJava(false);
} catch (UnsatisfiedLinkError error) {
throw new RuntimeException("can't load native libraries " + Build.CPU_ABI + " lookup folder " + NativeLoader.getAbiFolder());
}
new ForegroundDetector(this) { new ForegroundDetector(this) {
@Override @Override
public void onActivityStarted(Activity activity) { public void onActivityStarted(Activity activity) {

View file

@ -24,8 +24,8 @@ public class BuildVars {
public static boolean USE_CLOUD_STRINGS = true; public static boolean USE_CLOUD_STRINGS = true;
public static boolean CHECK_UPDATES = true; public static boolean CHECK_UPDATES = true;
public static boolean NO_SCOPED_STORAGE = Build.VERSION.SDK_INT <= 29; public static boolean NO_SCOPED_STORAGE = Build.VERSION.SDK_INT <= 29;
public static int BUILD_VERSION = 3249; public static int BUILD_VERSION = 3252;
public static String BUILD_VERSION_STRING = "9.5.7"; public static String BUILD_VERSION_STRING = "9.5.8";
public static int APP_ID = 4; public static int APP_ID = 4;
public static String APP_HASH = "014b35b6184100b085b0d0572f9b5103"; public static String APP_HASH = "014b35b6184100b085b0d0572f9b5103";

View file

@ -53,6 +53,7 @@ public final class EmuInputDevicesDetector {
} }
} }
} }
r.close();
return lines; return lines;
} catch (IOException e) { } catch (IOException e) {
FileLog.e(e); FileLog.e(e);

View file

@ -2277,7 +2277,8 @@ public class ImageLoader {
newPath = ApplicationLoader.applicationContext.getExternalFilesDir(null); newPath = ApplicationLoader.applicationContext.getExternalFilesDir(null);
telegramPath = new File(newPath, "Telegram"); telegramPath = new File(newPath, "Telegram");
} else { } else {
if (!(path.exists() ? path.isDirectory() : path.mkdirs()) || !path.canWrite()) { boolean isSdCard = !TextUtils.isEmpty(SharedConfig.storageCacheDir) && path.getAbsolutePath().startsWith(SharedConfig.storageCacheDir);
if (!isSdCard && !(path.exists() ? path.isDirectory() : path.mkdirs()) || !path.canWrite()) {
path = ApplicationLoader.applicationContext.getExternalFilesDir(null); path = ApplicationLoader.applicationContext.getExternalFilesDir(null);
} }
telegramPath = new File(path, "Telegram"); telegramPath = new File(path, "Telegram");

View file

@ -22,7 +22,7 @@ import java.util.zip.ZipFile;
public class NativeLoader { public class NativeLoader {
private final static int LIB_VERSION = 43; private final static int LIB_VERSION = 44;
private final static String LIB_NAME = "tmessages." + LIB_VERSION; private final static String LIB_NAME = "tmessages." + LIB_VERSION;
private final static String LIB_SO_NAME = "lib" + LIB_NAME + ".so"; private final static String LIB_SO_NAME = "lib" + LIB_NAME + ".so";
private final static String LOCALE_LIB_SO_NAME = "lib" + LIB_NAME + "loc.so"; private final static String LOCALE_LIB_SO_NAME = "lib" + LIB_NAME + "loc.so";
@ -127,36 +127,7 @@ public class NativeLoader {
FileLog.e(e); FileLog.e(e);
} }
String folder; String folder = getAbiFolder();
try {
String str = Build.CPU_ABI;
if (Build.CPU_ABI.equalsIgnoreCase("x86_64")) {
folder = "x86_64";
} else if (Build.CPU_ABI.equalsIgnoreCase("arm64-v8a")) {
folder = "arm64-v8a";
} else if (Build.CPU_ABI.equalsIgnoreCase("armeabi-v7a")) {
folder = "armeabi-v7a";
} else if (Build.CPU_ABI.equalsIgnoreCase("armeabi")) {
folder = "armeabi";
} else if (Build.CPU_ABI.equalsIgnoreCase("x86")) {
folder = "x86";
} else if (Build.CPU_ABI.equalsIgnoreCase("mips")) {
folder = "mips";
} else {
folder = "armeabi";
if (BuildVars.LOGS_ENABLED) {
FileLog.e("Unsupported arch: " + Build.CPU_ABI);
}
}
} catch (Exception e) {
FileLog.e(e);
folder = "armeabi";
}
String javaArch = System.getProperty("os.arch");
if (javaArch != null && javaArch.contains("686")) {
folder = "x86";
}
/*File destFile = getNativeLibraryDir(context); /*File destFile = getNativeLibraryDir(context);
if (destFile != null) { if (destFile != null) {
@ -209,6 +180,40 @@ public class NativeLoader {
} }
} }
public static String getAbiFolder() {
String folder;
try {
String str = Build.CPU_ABI;
if (Build.CPU_ABI.equalsIgnoreCase("x86_64")) {
folder = "x86_64";
} else if (Build.CPU_ABI.equalsIgnoreCase("arm64-v8a")) {
folder = "arm64-v8a";
} else if (Build.CPU_ABI.equalsIgnoreCase("armeabi-v7a")) {
folder = "armeabi-v7a";
} else if (Build.CPU_ABI.equalsIgnoreCase("armeabi")) {
folder = "armeabi";
} else if (Build.CPU_ABI.equalsIgnoreCase("x86")) {
folder = "x86";
} else if (Build.CPU_ABI.equalsIgnoreCase("mips")) {
folder = "mips";
} else {
folder = "armeabi";
if (BuildVars.LOGS_ENABLED) {
FileLog.e("Unsupported arch: " + Build.CPU_ABI);
}
}
} catch (Exception e) {
FileLog.e(e);
folder = "armeabi";
}
String javaArch = System.getProperty("os.arch");
if (javaArch != null && javaArch.contains("686")) {
folder = "x86";
}
return folder;
}
private static native void init(String path, boolean enable); private static native void init(String path, boolean enable);
public static boolean loaded() { public static boolean loaded() {

View file

@ -4837,7 +4837,7 @@ public class DialogCell extends BaseCell {
} }
return false; return false;
} }
int messageHash = message == null ? 0 : message.getId(); int messageHash = message == null ? 0 : message.getId() + message.hashCode();
Integer printingType = null; Integer printingType = null;
long readHash = dialog.read_inbox_max_id + ((long) dialog.read_outbox_max_id << 8) + ((long) (dialog.unread_count + (dialog.unread_mark ? -1 : 0)) << 16) + long readHash = dialog.read_inbox_max_id + ((long) dialog.read_outbox_max_id << 8) + ((long) (dialog.unread_count + (dialog.unread_mark ? -1 : 0)) << 16) +
(dialog.unread_reactions_count > 0 ? (1 << 18) : 0) + (dialog.unread_reactions_count > 0 ? (1 << 18) : 0) +

View file

@ -134,7 +134,7 @@ public class DialogsRequestedEmptyCell extends LinearLayout implements Notificat
@Override @Override
protected void onDetachedFromWindow() { protected void onDetachedFromWindow() {
super.onDetachedFromWindow(); super.onDetachedFromWindow();
NotificationCenter.getInstance(currentAccount).addObserver(this, NotificationCenter.diceStickersDidLoad); NotificationCenter.getInstance(currentAccount).removeObserver(this, NotificationCenter.diceStickersDidLoad);
} }
@Override @Override

View file

@ -3507,6 +3507,12 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
} }
} }
@Override
protected void onMeasure(int widthSpec, int heightSpec) {
saveScrollPosition();
super.onMeasure(widthSpec, heightSpec);
}
@Override @Override
protected void onLayout(boolean changed, int l, int t, int r, int b) { protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b); super.onLayout(changed, l, t, r, b);
@ -8748,28 +8754,24 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
if (chatListView != null && chatLayoutManager != null && chatAdapter != null) { if (chatListView != null && chatLayoutManager != null && chatAdapter != null) {
if (chatListView.getPaddingTop() != p) { if (chatListView.getPaddingTop() != p) {
int firstVisPos = chatLayoutManager.findFirstVisibleItemPosition();
int lastVisPos = chatLayoutManager.findLastVisibleItemPosition();
int top = 0; int top = 0;
MessageObject scrollToMessageObject = null; MessageObject scrollToMessageObject = null;
if (firstVisPos != RecyclerView.NO_POSITION) { for (int i = 0; i < chatListView.getChildCount(); i++) {
for (int i = firstVisPos; i <= lastVisPos; i++) { View v = chatListView.getChildAt(i);
View v = chatLayoutManager.findViewByPosition(i);
if (v instanceof ChatMessageCell) { if (v instanceof ChatMessageCell) {
scrollToMessageObject = ((ChatMessageCell) v).getMessageObject(); scrollToMessageObject = ((ChatMessageCell) v).getMessageObject();
top = chatListView.getMeasuredHeight() - v.getBottom() - chatListView.getPaddingBottom(); top = getScrollingOffsetForView(v);
break; break;
} else if (v instanceof ChatActionCell) { } else if (v instanceof ChatActionCell) {
scrollToMessageObject = ((ChatActionCell) v).getMessageObject(); scrollToMessageObject = ((ChatActionCell) v).getMessageObject();
top = chatListView.getMeasuredHeight() - v.getBottom() - chatListView.getPaddingBottom(); top = getScrollingOffsetForView(v);
break; break;
} }
} }
}
chatListView.setPadding(0, p, 0, AndroidUtilities.dp(3) + blurredViewBottomOffset); chatListView.setPadding(0, p, 0, AndroidUtilities.dp(3) + blurredViewBottomOffset);
if (firstVisPos != RecyclerView.NO_POSITION && scrollToMessageObject != null) { if (scrollToMessageObject != null) {
chatAdapter.updateRowsSafe(); chatAdapter.updateRowsSafe();
int index = messages.indexOf(scrollToMessageObject); int index = messages.indexOf(scrollToMessageObject);
if (index >= 0) { if (index >= 0) {
@ -15843,24 +15845,20 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
startLoadFromMessageId = 0; startLoadFromMessageId = 0;
} }
if (newRowsCount > 0) { if (newRowsCount > 0) {
int firstVisPos = chatLayoutManager.findFirstVisibleItemPosition();
int lastVisPos = chatLayoutManager.findLastVisibleItemPosition();
int top = 0; int top = 0;
MessageObject scrollToMessageObject = null; MessageObject scrollToMessageObject = null;
if (firstVisPos != RecyclerView.NO_POSITION) { for (int i = 0; i < chatListView.getChildCount(); i++) {
for (int i = firstVisPos; i <= lastVisPos; i++) { View v = chatListView.getChildAt(i);
View v = chatLayoutManager.findViewByPosition(i);
if (v instanceof ChatMessageCell) { if (v instanceof ChatMessageCell) {
scrollToMessageObject = ((ChatMessageCell) v).getMessageObject(); scrollToMessageObject = ((ChatMessageCell) v).getMessageObject();
top = chatListView.getMeasuredHeight() - v.getBottom() - chatListView.getPaddingBottom(); top = getScrollingOffsetForView(v);
break; break;
} else if (v instanceof ChatActionCell) { } else if (v instanceof ChatActionCell) {
scrollToMessageObject = ((ChatActionCell) v).getMessageObject(); scrollToMessageObject = ((ChatActionCell) v).getMessageObject();
top = chatListView.getMeasuredHeight() - v.getBottom() - chatListView.getPaddingBottom(); top = getScrollingOffsetForView(v);
break; break;
} }
} }
}
if (!postponedScroll) { if (!postponedScroll) {
chatAdapter.notifyItemRangeInserted(1, newRowsCount); chatAdapter.notifyItemRangeInserted(1, newRowsCount);
@ -15959,24 +15957,20 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
} }
} else { } else {
if (newRowsCount != 0) { if (newRowsCount != 0) {
int firstVisPos = chatLayoutManager.findFirstVisibleItemPosition();
int lastVisPos = chatLayoutManager.findLastVisibleItemPosition();
int top = 0; int top = 0;
MessageObject scrollToMessageObject = null; MessageObject scrollToMessageObject = null;
if (firstVisPos != RecyclerView.NO_POSITION) { for (int i = 0; i < chatListView.getChildCount(); i++) {
for (int i = firstVisPos; i <= lastVisPos; i++) { View v = chatListView.getChildAt(i);
View v = chatLayoutManager.findViewByPosition(i);
if (v instanceof ChatMessageCell) { if (v instanceof ChatMessageCell) {
scrollToMessageObject = ((ChatMessageCell) v).getMessageObject(); scrollToMessageObject = ((ChatMessageCell) v).getMessageObject();
top = chatListView.getMeasuredHeight() - v.getBottom() - chatListView.getPaddingBottom(); top = getScrollingOffsetForView(v);
break; break;
} else if (v instanceof ChatActionCell) { } else if (v instanceof ChatActionCell) {
scrollToMessageObject = ((ChatActionCell) v).getMessageObject(); scrollToMessageObject = ((ChatActionCell) v).getMessageObject();
top = chatListView.getMeasuredHeight() - v.getBottom() - chatListView.getPaddingBottom(); top = getScrollingOffsetForView(v);
break; break;
} }
} }
}
int insertStart = chatAdapter.messagesEndRow; int insertStart = chatAdapter.messagesEndRow;
int loadingUpRow = chatAdapter.loadingUpRow; int loadingUpRow = chatAdapter.loadingUpRow;
chatAdapter.updateRowsInternal(); chatAdapter.updateRowsInternal();
@ -18268,6 +18262,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
} }
} }
private int getScrollingOffsetForView(View v) {
return chatListView.getMeasuredHeight() - v.getBottom() - chatListView.getPaddingBottom();
}
private boolean updateMessageTranslation(MessageObject messageObject) { private boolean updateMessageTranslation(MessageObject messageObject) {
if (messageObject == null || messageObject.messageOwner == null) { if (messageObject == null || messageObject.messageOwner == null) {
return false; return false;
@ -19438,7 +19436,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
} }
} else { } else {
if (child != null) { if (child != null) {
chatLayoutManager.scrollToPositionWithOffset(lastVisible + 1, chatListView.getMeasuredHeight() - child.getBottom() - chatListView.getPaddingBottom()); chatLayoutManager.scrollToPositionWithOffset(lastVisible + 1, getScrollingOffsetForView(child));
} }
} }
if (newMentionsCount != 0 && mentiondownButtonCounter != null) { if (newMentionsCount != 0 && mentiondownButtonCounter != null) {
@ -19488,6 +19486,32 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
} }
} }
private void saveScrollPosition() {
if (chatListView == null || chatLayoutManager == null || chatLayoutManager.hasPendingScrollPosition()) {
return;
}
int top = 0;
MessageObject scrollToMessageObject = null;
for (int i = 0; i < chatListView.getChildCount(); i++) {
View v = chatListView.getChildAt(i);
if (v instanceof ChatMessageCell) {
scrollToMessageObject = ((ChatMessageCell) v).getMessageObject();
top = getScrollingOffsetForView(v);
break;
} else if (v instanceof ChatActionCell) {
scrollToMessageObject = ((ChatActionCell) v).getMessageObject();
top = getScrollingOffsetForView(v);
break;
}
}
if (scrollToMessageObject != null) {
int scrollToIndex = messages.indexOf(scrollToMessageObject);
if (scrollToIndex > 0) {
chatLayoutManager.scrollToPositionWithOffset(chatAdapter.messagesStartRow + scrollToIndex, top);
}
}
}
private int getSponsoredMessagesCount() { private int getSponsoredMessagesCount() {
int sponsoredMessagesCount = 0; int sponsoredMessagesCount = 0;
while (sponsoredMessagesCount < messages.size()) { while (sponsoredMessagesCount < messages.size()) {
@ -26123,7 +26147,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
int unreadMessageIndex = messages.indexOf(unreadMessageObject); int unreadMessageIndex = messages.indexOf(unreadMessageObject);
if (unreadMessageIndex >= 0) { if (unreadMessageIndex >= 0) {
lastVisibleItem = chatAdapter.messagesStartRow + messages.indexOf(unreadMessageObject); lastVisibleItem = chatAdapter.messagesStartRow + messages.indexOf(unreadMessageObject);
top = chatListView.getMeasuredHeight() - child.getBottom() - chatListView.getPaddingBottom(); top = getScrollingOffsetForView(child);
} }
break; break;
} }
@ -26185,7 +26209,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
} }
} }
if (lastVisibleItem != RecyclerView.NO_POSITION) { if (lastVisibleItem != RecyclerView.NO_POSITION) {
// chatLayoutManager.scrollToPositionWithOffset(lastVisibleItem, top); chatLayoutManager.scrollToPositionWithOffset(lastVisibleItem, top);
} }
} }
@ -28288,7 +28312,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
int unreadMessageIndex = messages.indexOf(unreadMessageObject); int unreadMessageIndex = messages.indexOf(unreadMessageObject);
if (unreadMessageIndex >= 0) { if (unreadMessageIndex >= 0) {
lastVisibleItem = messagesStartRow + messages.indexOf(unreadMessageObject); lastVisibleItem = messagesStartRow + messages.indexOf(unreadMessageObject);
top = chatListView.getMeasuredHeight() - child.getBottom() - chatListView.getPaddingBottom(); top = getScrollingOffsetForView(child);
} }
break; break;
} }

View file

@ -16,6 +16,7 @@ import android.text.Layout;
import android.text.SpannableStringBuilder; import android.text.SpannableStringBuilder;
import android.text.Spanned; import android.text.Spanned;
import android.text.TextPaint; import android.text.TextPaint;
import android.text.TextUtils;
import android.text.style.ClickableSpan; import android.text.style.ClickableSpan;
import android.util.TypedValue; import android.util.TypedValue;
import android.view.Gravity; import android.view.Gravity;
@ -357,11 +358,11 @@ public class PremiumPreviewBottomSheet extends BottomSheetWithRecyclerListView i
if (isOutboundGift) { if (isOutboundGift) {
titleView[0].setText(AndroidUtilities.replaceSingleTag(LocaleController.formatString(R.string.TelegramPremiumUserGiftedPremiumOutboundDialogTitleWithPlural, user != null ? user.first_name : "", LocaleController.formatPluralString("GiftMonths", giftTier.getMonths())), Theme.key_windowBackgroundWhiteBlueButton, AndroidUtilities.REPLACING_TAG_TYPE_LINK, null)); titleView[0].setText(AndroidUtilities.replaceSingleTag(LocaleController.formatString(R.string.TelegramPremiumUserGiftedPremiumOutboundDialogTitleWithPlural, user != null ? user.first_name : "", LocaleController.formatPluralString("GiftMonths", giftTier.getMonths())), Theme.key_windowBackgroundWhiteBlueButton, AndroidUtilities.REPLACING_TAG_TYPE_LINK, null));
subtitleView.setText(AndroidUtilities.replaceSingleTag(LocaleController.formatString(R.string.TelegramPremiumUserGiftedPremiumOutboundDialogSubtitle, user != null ? user.first_name : ""), Theme.key_windowBackgroundWhiteBlueButton, AndroidUtilities.REPLACING_TAG_TYPE_LINK, null)); subtitleView.setText(AndroidUtilities.replaceSingleTag(LocaleController.formatString(R.string.TelegramPremiumUserGiftedPremiumOutboundDialogSubtitle, user != null ? user.first_name : ""), Theme.key_windowBackgroundWhiteBlueButton, AndroidUtilities.REPLACING_TAG_TYPE_LINK, null));
} else if (user != null && user.id == 777000) { } else if (user == null || TextUtils.isEmpty(user.first_name) || user.id == 777000) {
titleView[0].setText(AndroidUtilities.replaceSingleTag(LocaleController.formatString(R.string.TelegramPremiumUserGiftedPremiumDialogTitleWithPluralSomeone, LocaleController.formatPluralString("GiftMonths", giftTier.getMonths())), Theme.key_windowBackgroundWhiteBlueButton, AndroidUtilities.REPLACING_TAG_TYPE_LINK, null)); titleView[0].setText(AndroidUtilities.replaceSingleTag(LocaleController.formatString(R.string.TelegramPremiumUserGiftedPremiumDialogTitleWithPluralSomeone, LocaleController.formatPluralString("GiftMonths", giftTier.getMonths())), Theme.key_windowBackgroundWhiteBlueButton, AndroidUtilities.REPLACING_TAG_TYPE_LINK, null));
subtitleView.setText(AndroidUtilities.replaceTags(LocaleController.getString(R.string.TelegramPremiumUserGiftedPremiumDialogSubtitle))); subtitleView.setText(AndroidUtilities.replaceTags(LocaleController.getString(R.string.TelegramPremiumUserGiftedPremiumDialogSubtitle)));
} else { } else {
titleView[0].setText(AndroidUtilities.replaceSingleTag(LocaleController.formatString(R.string.TelegramPremiumUserGiftedPremiumDialogTitleWithPlural, user != null ? user.first_name : "", LocaleController.formatPluralString("GiftMonths", giftTier.getMonths())), Theme.key_windowBackgroundWhiteBlueButton, AndroidUtilities.REPLACING_TAG_TYPE_LINK, null)); titleView[0].setText(AndroidUtilities.replaceSingleTag(LocaleController.formatString(R.string.TelegramPremiumUserGiftedPremiumDialogTitleWithPlural, user.first_name, LocaleController.formatPluralString("GiftMonths", giftTier.getMonths())), Theme.key_windowBackgroundWhiteBlueButton, AndroidUtilities.REPLACING_TAG_TYPE_LINK, null));
subtitleView.setText(AndroidUtilities.replaceTags(LocaleController.getString(R.string.TelegramPremiumUserGiftedPremiumDialogSubtitle))); subtitleView.setText(AndroidUtilities.replaceTags(LocaleController.getString(R.string.TelegramPremiumUserGiftedPremiumDialogSubtitle)));
} }
} else { } else {

View file

@ -294,7 +294,6 @@ public class RLottieDrawable extends BitmapDrawable implements Animatable, Bitma
if (onAnimationEndListener != null) { if (onAnimationEndListener != null) {
onAnimationEndListener = null; onAnimationEndListener = null;
} }
invalidateInternal();
} }
public void setOnFinishCallback(Runnable callback, int frame) { public void setOnFinishCallback(Runnable callback, int frame) {

View file

@ -94,7 +94,7 @@ public class StickerCategoriesListView extends RecyclerListView {
public static void preload(int account, @CategoriesType int type) { public static void preload(int account, @CategoriesType int type) {
fetcher.fetch(account, type, emojiGroups -> { fetcher.fetch(account, type, emojiGroups -> {
if (emojiGroups.groups == null) { if (emojiGroups == null || emojiGroups.groups == null) {
return; return;
} }
for (TLRPC.TL_emojiGroup group : emojiGroups.groups) { for (TLRPC.TL_emojiGroup group : emojiGroups.groups) {

View file

@ -8683,6 +8683,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter.
} else if (id == NotificationCenter.dialogsUnreadReactionsCounterChanged) { } else if (id == NotificationCenter.dialogsUnreadReactionsCounterChanged) {
updateVisibleRows(0); updateVisibleRows(0);
} else if (id == NotificationCenter.emojiLoaded) { } else if (id == NotificationCenter.emojiLoaded) {
if (viewPages != null) {
for (int i = 0; i < viewPages.length; ++i) { for (int i = 0; i < viewPages.length; ++i) {
final RecyclerListView listView = viewPages[i].listView; final RecyclerListView listView = viewPages[i].listView;
if (listView != null) { if (listView != null) {
@ -8694,6 +8695,7 @@ public class DialogsActivity extends BaseFragment implements NotificationCenter.
} }
} }
} }
}
if (filterTabsView != null) { if (filterTabsView != null) {
filterTabsView.getTabsContainer().invalidateViews(); filterTabsView.getTabsContainer().invalidateViews();
} }

View file

@ -1682,9 +1682,9 @@ public class LoginActivity extends BaseFragment {
if (obj.optBoolean("basicIntegrity") && obj.optBoolean("ctsProfileMatch")) { if (obj.optBoolean("basicIntegrity") && obj.optBoolean("ctsProfileMatch")) {
ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> { ConnectionsManager.getInstance(currentAccount).sendRequest(req, (response, error) -> {
if (response instanceof TLRPC.TL_boolTrue) {
needHideProgress(false); needHideProgress(false);
isRequestingFirebaseSms = false; isRequestingFirebaseSms = false;
if (response instanceof TLRPC.TL_boolTrue) {
res.type.verifiedFirebase = true; res.type.verifiedFirebase = true;
AndroidUtilities.runOnUIThread(() -> fillNextCodeParams(params, res, animate)); AndroidUtilities.runOnUIThread(() -> fillNextCodeParams(params, res, animate));
} else { } else {
@ -3654,19 +3654,6 @@ public class LoginActivity extends BaseFragment {
wrongCode.setPadding(0, AndroidUtilities.dp(4), 0, AndroidUtilities.dp(4)); wrongCode.setPadding(0, AndroidUtilities.dp(4), 0, AndroidUtilities.dp(4));
errorViewSwitcher.addView(wrongCode, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER)); errorViewSwitcher.addView(wrongCode, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER));
if (currentType != AUTH_TYPE_FRAGMENT_SMS) {
if (currentType == AUTH_TYPE_MESSAGE) {
if (nextType == AUTH_TYPE_FLASH_CALL || nextType == AUTH_TYPE_CALL || nextType == AUTH_TYPE_MISSED_CALL) {
problemText.setText(LocaleController.getString("DidNotGetTheCodePhone", R.string.DidNotGetTheCodePhone));
} else if (nextType == 0) {
problemText.setText(LocaleController.getString("DidNotGetTheCode", R.string.DidNotGetTheCode));
} else {
problemText.setText(LocaleController.getString("DidNotGetTheCodeSms", R.string.DidNotGetTheCodeSms));
}
} else {
problemText.setText(LocaleController.getString("DidNotGetTheCode", R.string.DidNotGetTheCode));
}
}
if (centerContainer == null) { if (centerContainer == null) {
bottomContainer = new FrameLayout(context); bottomContainer = new FrameLayout(context);
bottomContainer.addView(errorViewSwitcher, LayoutHelper.createFrame(currentType == VIEW_CODE_FRAGMENT_SMS ? LayoutHelper.MATCH_PARENT : LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM, 0, 0, 0, 32)); bottomContainer.addView(errorViewSwitcher, LayoutHelper.createFrame(currentType == VIEW_CODE_FRAGMENT_SMS ? LayoutHelper.MATCH_PARENT : LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM, 0, 0, 0, 32));
@ -3998,6 +3985,20 @@ public class LoginActivity extends BaseFragment {
} }
confirmTextView.setText(str); confirmTextView.setText(str);
if (currentType != AUTH_TYPE_FRAGMENT_SMS) {
if (currentType == AUTH_TYPE_MESSAGE) {
if (nextType == AUTH_TYPE_FLASH_CALL || nextType == AUTH_TYPE_CALL || nextType == AUTH_TYPE_MISSED_CALL) {
problemText.setText(LocaleController.getString("DidNotGetTheCodePhone", R.string.DidNotGetTheCodePhone));
} else if (nextType == 0) {
problemText.setText(LocaleController.getString("DidNotGetTheCode", R.string.DidNotGetTheCode));
} else {
problemText.setText(LocaleController.getString("DidNotGetTheCodeSms", R.string.DidNotGetTheCodeSms));
}
} else {
problemText.setText(LocaleController.getString("DidNotGetTheCode", R.string.DidNotGetTheCode));
}
}
if (currentType != AUTH_TYPE_FLASH_CALL) { if (currentType != AUTH_TYPE_FLASH_CALL) {
showKeyboard(codeFieldContainer.codeField[0]); showKeyboard(codeFieldContainer.codeField[0]);
codeFieldContainer.codeField[0].requestFocus(); codeFieldContainer.codeField[0].requestFocus();
@ -4015,7 +4016,8 @@ public class LoginActivity extends BaseFragment {
if (problemText != null) { if (problemText != null) {
problemText.setVisibility(VISIBLE); problemText.setVisibility(VISIBLE);
} }
} else if (currentType == AUTH_TYPE_FLASH_CALL && (nextType == AUTH_TYPE_CALL || nextType == AUTH_TYPE_SMS)) { } else if (currentType == AUTH_TYPE_FLASH_CALL) {
if (nextType == AUTH_TYPE_CALL || nextType == AUTH_TYPE_SMS || nextType == AUTH_TYPE_MISSED_CALL) {
setProblemTextVisible(false); setProblemTextVisible(false);
timeText.setVisibility(VISIBLE); timeText.setVisibility(VISIBLE);
problemText.setVisibility(GONE); problemText.setVisibility(GONE);
@ -4024,12 +4026,13 @@ public class LoginActivity extends BaseFragment {
} else if (nextType == AUTH_TYPE_SMS) { } else if (nextType == AUTH_TYPE_SMS) {
timeText.setText(LocaleController.formatString("SmsAvailableIn", R.string.SmsAvailableIn, 1, 0)); timeText.setText(LocaleController.formatString("SmsAvailableIn", R.string.SmsAvailableIn, 1, 0));
} }
}
String callLogNumber = restore ? AndroidUtilities.obtainLoginPhoneCall(pattern) : null; String callLogNumber = restore ? AndroidUtilities.obtainLoginPhoneCall(pattern) : null;
if (callLogNumber != null) { if (callLogNumber != null) {
onNextPressed(callLogNumber); onNextPressed(callLogNumber);
} else if (catchedPhone != null) { } else if (catchedPhone != null) {
onNextPressed(catchedPhone); onNextPressed(catchedPhone);
} else { } else if (nextType == AUTH_TYPE_CALL || nextType == AUTH_TYPE_SMS || nextType == AUTH_TYPE_MISSED_CALL) {
createTimer(); createTimer();
} }
} else if (currentType == AUTH_TYPE_SMS && (nextType == AUTH_TYPE_CALL || nextType == AUTH_TYPE_FLASH_CALL)) { } else if (currentType == AUTH_TYPE_SMS && (nextType == AUTH_TYPE_CALL || nextType == AUTH_TYPE_FLASH_CALL)) {

View file

@ -13,12 +13,12 @@
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true # org.gradle.parallel=true
#Sat Mar 12 05:53:50 MSK 2016 #Sat Mar 12 05:53:50 MSK 2016
APP_VERSION_CODE=3249 APP_VERSION_CODE=3252
APP_VERSION_NAME=9.5.7 APP_VERSION_NAME=9.5.8
APP_PACKAGE=org.telegram.messenger APP_PACKAGE=org.telegram.messenger
RELEASE_KEY_PASSWORD=android RELEASE_KEY_PASSWORD=TelegramAndroidPswd
RELEASE_KEY_ALIAS=androidkey RELEASE_KEY_ALIAS=tmessages
RELEASE_STORE_PASSWORD=android RELEASE_STORE_PASSWORD=TelegramAndroidPswd
org.gradle.jvmargs=-Xmx4096M -XX:MaxPermSize=4096m org.gradle.jvmargs=-Xmx4096M -XX:MaxPermSize=4096m
org.gradle.daemon=true org.gradle.daemon=true
org.gradle.parallel=true org.gradle.parallel=true